Jelajahi Sumber

Merge branch 'feature_电商平台' of elab-damai-h5/h5-dm-orderFront into master

周建思 1 bulan lalu
induk
melakukan
eea8f49f66

+ 7 - 7
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>后台管理系统</title>
+    <title>商品零售+点餐系统</title>
     <style>
       * {
         margin: 0;
@@ -17,13 +17,13 @@
         height: 100vh;
         width: 100vw;
       }
-  
+
       .circular {
         height: 42px;
         width: 42px;
         animation: loading-rotate 2s linear infinite;
       }
-  
+
       .circular .path {
         animation: loading-dash 1.5s ease-in-out infinite;
         stroke-dasharray: 90, 150;
@@ -32,20 +32,20 @@
         stroke: #4073fa;
         stroke-linecap: round;
       }
-  
+
       @keyframes loading-rotate {
         100% {
           transform: rotate(1turn);
         }
       }
-  
+
       @keyframes loading-dash {
-  
+
         0% {
           stroke-dasharray: 90, 150;
           stroke-dashoffset: -40px;
         }
-  
+
         100% {
           stroke-dasharray: 90, 150;
           stroke-dashoffset: -120px;

+ 22 - 0
src/api/goods/category.ts

@@ -0,0 +1,22 @@
+import request from '@/utils/request'
+
+// 商品分类列表
+export function goodsCategoryPage(params?: any) {
+    return request.get({url: '/product/listCategory', params})
+}
+
+// 添加商品分类
+export function goodsCategoryAdd(params: any) {
+    return request.post({url: '/product/saveCategory', params})
+}
+
+// 编辑商品分类
+export function goodsCategoryEdit(params: any) {
+    return request.post({url: '/product/saveCategory', params})
+}
+
+// 删除商品分类
+export function goodsCategoryDelete(params: any) {
+    return request.post({url: '/product/saveCategory', params})
+}
+

+ 17 - 0
src/api/goods/list.ts

@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+// 商品列表
+export function goodsPage(params?: any) {
+    return request.get({url: '/product/listByShop', params})
+}
+
+// 商品列表
+export function goodsEdit(params?: any) {
+    return request.post({url: '/product/save', params})
+}
+
+// 添加商品
+export function goodsDetail(params: any) {
+    return request.get({url: '/product/queryById', params})
+}
+

+ 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.post({ 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 })
-}
+}

+ 2 - 1
src/api/user.ts

@@ -3,7 +3,8 @@ import request from '@/utils/request'
 
 // 登录
 export function login(params: Record<string, any>) {
-    return request.post({ url: '/system/login', params: { ...params, terminal: config.terminal } })
+    // return request.post({ url: '/membership/queryMemberUser', params }, { urlPrefix: '/elab-marketing-content' })
+    return request.post({ url: '/login/captchaLogin', params: { ...params, terminal: config.terminal } },{ urlPrefix: '/elab-marketing-analyse' })
 }
 
 // 登录

+ 20 - 17
src/components/upload/index.vue

@@ -48,7 +48,7 @@ import feedback from '@/utils/feedback'
 import type { ElUpload, UploadProps, UploadRawFile } from 'element-plus'
 import { RequestCodeEnum } from '@/enums/requestEnums'
 import ImageCompressor from 'image-compressor.js'
-import { getToken,getUserId,getBrandId,getHouseId } from '@/utils/auth'
+import {getToken, getUserId, getBrandId, getHouseId, getShopId} from '@/utils/auth'
 export default defineComponent({
     components: {},
     props: {
@@ -87,6 +87,7 @@ export default defineComponent({
         const brandId = getBrandId();
         const houseId = getHouseId();
         const token = getToken();
+        const shopId = getShopId();
         const headers = computed(() => ({
             ['like-admin']: userStore.token,
             version: config.version,
@@ -105,29 +106,31 @@ export default defineComponent({
             // 更新上传参数
             uploadData.value = {
                 ...props.data,
-                fileName: rawFile.name
+                fileName: rawFile.name,
+              shopId: shopId
             }
-            
-            let q = 0.5
-            if (rawFile.size > 1000000 && rawFile.size < 5000000) {
+            if(props.type === 'image'){
+              let q = 0.5
+              if (rawFile.size > 1000000 && rawFile.size < 5000000) {
                 q = 0.5
-            } else if (rawFile.size >= 5000000 && rawFile.size < 10000000) {
+              } else if (rawFile.size >= 5000000 && rawFile.size < 10000000) {
                 q = 0.25
-            } else if (rawFile.size >= 10000000) {
+              } else if (rawFile.size >= 10000000) {
                 q = 0.1
-            } else {
+              } else {
                 return true
-            }
-            return new Promise((resolve) => {
+              }
+              return new Promise((resolve) => {
                 new ImageCompressor(rawFile, {
-                    quality: q, //压缩质量
-                    checkOrientation: false, //图片翻转,默认为false
-                    success(result: any) {
-                        console.log(result)
-                        resolve(result)
-                    }
+                  quality: q, //压缩质量
+                  checkOrientation: false, //图片翻转,默认为false
+                  success(result: any) {
+                    console.log(result)
+                    resolve(result)
+                  }
                 })
-            })
+              })
+            }
         }
 
         const handleProgress = (event: any, file: any, fileLists: any[]) => {

+ 1 - 1
src/config/index.ts

@@ -1,6 +1,6 @@
 const config = {
     terminal: 1, //终端
-    title: '后台管理系统', //网站默认标题
+    title: '商品零售+点餐系统', //网站默认标题
     version: '1.4.0', //版本号
     baseUrl: `${import.meta.env.VITE_APP_BASE_URL || 'http://203.156.249.2:5555'}/`, //请求接口域名 http://192.168.50.19:5555/elab-marketing-file
     urlPrefix: 'elab-marketing-file/api', //请求默认前缀

+ 2 - 0
src/enums/cacheEnums.ts

@@ -6,3 +6,5 @@ export const TOKEN_KEY = 'token'
 export const ACCOUNT_KEY = 'account'
 //设置
 export const SETTING_KEY = 'setting'
+//设置
+export const SHOP_ID = 'shop_id'

+ 3 - 3
src/layout/default/components/header/user-drop-down.vue

@@ -3,17 +3,17 @@
         <div class="flex items-center">
             <el-avatar :size="34" :src="userInfo.avatar" />
             <div class="ml-3 mr-1">{{ userInfo.nickname }}</div>
-            <!-- <icon name="el-icon-ArrowDown" /> -->
+             <icon name="el-icon-ArrowDown" />
         </div>
 
-        <!-- <template #dropdown>
+         <template #dropdown>
             <el-dropdown-menu>
                 <router-link to="/user/setting">
                     <el-dropdown-item>个人设置</el-dropdown-item>
                 </router-link>
                 <el-dropdown-item command="logout">退出登录</el-dropdown-item>
             </el-dropdown-menu>
-        </template> -->
+        </template>
     </el-dropdown>
 </template>
 

+ 26 - 5
src/permission.ts

@@ -10,23 +10,44 @@ import useUserStore from './stores/modules/user'
 import { INDEX_ROUTE, INDEX_ROUTE_NAME } from './router/routes'
 import { PageEnum } from './enums/pageEnum'
 import useTabsStore from './stores/modules/multipleTabs'
-import { clearAuthInfo } from './utils/auth'
+import { clearAuthInfo, getShopId } from './utils/auth'
 import config from './config'
 
 // NProgress配置
 NProgress.configure({ showSpinner: false })
 
+var shopId = getShopId();
 const loginPath = PageEnum.LOGIN
 const defaultPath = PageEnum.INDEX
 // 免登录白名单
 const whiteList: string[] = [PageEnum.LOGIN, PageEnum.ERROR_403]
+
+// 检测店铺ID变化并刷新页面的函数
+function checkShopIdChange() {
+    const currentShopId = getShopId();
+    if (shopId !== currentShopId && currentShopId && shopId) {
+        console.log('检测到店铺ID变化:', shopId, '->', currentShopId);
+        shopId = currentShopId;
+        // 刷新页面以更新数据
+        window.location.reload();
+        return true;
+    }
+    return false;
+}
+
 router.beforeEach(async (to, from, next) => {
     // 开始 Progress Bar
     NProgress.start()
+    
+    // 检测店铺ID变化
+    if (checkShopIdChange()) {
+        return; // 如果检测到变化并刷新页面,直接返回
+    }
+    
     document.title = to.meta.title ?? config.title
     const userStore = useUserStore()
     const tabsStore = useTabsStore()
-    console.warn("***userStore***",userStore.token,to.path)
+    console.warn("***userStore***",shopId,userStore.token,to.path)
     if (whiteList.includes(to.path)) {
         // 在免登录白名单,直接进入
         next()
@@ -49,7 +70,7 @@ router.beforeEach(async (to, from, next) => {
                 // 没有有效路由跳转到403页面
                 if (!routeName) {
                     clearAuthInfo()
-                    next(PageEnum.ERROR_403)
+                    next(PageEnum.LOGIN)
                     return
                 }
                 tabsStore.setRouteName(routeName!)
@@ -81,8 +102,8 @@ router.beforeEach(async (to, from, next) => {
         }
     } else {
         console.warn("***userStore-没有token***")
-        next(PageEnum.ERROR_403)
-        // next({ path: loginPath, query: { redirect: to.fullPath } })
+        // next(PageEnum.ERROR_403)
+        next({ path: loginPath, query: { redirect: to.fullPath } })
     }
 })
 

+ 24 - 15
src/stores/modules/user.ts

@@ -1,11 +1,12 @@
-import { defineStore } from 'pinia'
+import {defineStore} from 'pinia'
 import cache from '@/utils/cache'
-import type { RouteRecordRaw } from 'vue-router'
-import { getUserInfo, login, logout, getMenu } from '@/api/user'
-import router, { filterAsyncRoutes } from '@/router'
-import { TOKEN_KEY } from '@/enums/cacheEnums'
-import { PageEnum } from '@/enums/pageEnum'
-import { clearAuthInfo, getHouseId, getToken, getBrandId, getUserId} from '@/utils/auth'
+import type {RouteRecordRaw} from 'vue-router'
+import {getMenu, getUserInfo, login} from '@/api/user'
+import router, {filterAsyncRoutes} from '@/router'
+import {TOKEN_KEY} from '@/enums/cacheEnums'
+import {PageEnum} from '@/enums/pageEnum'
+import {clearAuthInfo, getBrandId, getHouseId, getToken, getUserId} from '@/utils/auth'
+
 export interface UserState {
     token: string
     houseId: string
@@ -43,18 +44,24 @@ const useUserStore = defineStore({
             this.perms = []
         },
         login(playload: any) {
-            const { account, password, code, uuid } = playload
+            const { mobile, passWord, code, uuid } = playload
             return new Promise((resolve, reject) => {
                 login({
-                    username: account,
-                    password,
+                    mobile: mobile,
+                    passWord,
                     code,
                     uuid
                 })
                     .then((data) => {
-                        this.token = data.token
-                        cache.set(TOKEN_KEY, data.token)
-                        resolve(data)
+                        this.token = data.single.token
+                        cache.set(TOKEN_KEY, data.single.token)
+                        window.localStorage.setItem("like_admin_token",data.single.token)
+                        window.localStorage.setItem("like_admin_brandId",data.single.brandId)
+                        window.localStorage.setItem("like_admin_userId",data.single.dataUserId)
+                        if(data.single.type === 2 && data.single.houseList.length == 1){
+                            window.localStorage.setItem("like_admin_houseId",data.single.houseList[0].houseId)
+                        }
+                        resolve(data.single)
                     })
                     .catch((error) => {
                         reject(error)
@@ -62,7 +69,7 @@ const useUserStore = defineStore({
             })
         },
         logout() {
-            return new Promise((resolve, reject) => {
+            /*return new Promise((resolve, reject) => {
                 logout()
                     .then(async (data) => {
                         this.token = ''
@@ -73,7 +80,9 @@ const useUserStore = defineStore({
                     .catch((error) => {
                         reject(error)
                     })
-            })
+            })*/
+            clearAuthInfo()
+            router.push(PageEnum.LOGIN)
         },
         getUserInfo() {
             return new Promise((resolve, reject) => {

+ 17 - 23
src/utils/auth.ts

@@ -1,15 +1,5 @@
-import { TOKEN_KEY } from '@/enums/cacheEnums'
-import { resetRouter } from '@/router'
-import useTabsStore from '@/stores/modules/multipleTabs'
-import useUserStore from '@/stores/modules/user'
+import {SHOP_ID, TOKEN_KEY} from '@/enums/cacheEnums'
 import cache from './cache'
-import {
-    ElMessage,
-    ElMessageBox,
-    ElNotification,
-    ElLoading,
-    type ElMessageBoxOptions
-} from 'element-plus'
 
 export function getToken() {
     return cache.get(TOKEN_KEY)
@@ -26,23 +16,27 @@ export function getHouseId() {
 export function getUserId() {
     return cache.get("userId")
 }
+
+
+export function getShopId() {
+    if (cache.get(SHOP_ID))
+        return JSON.parse(<string>cache.get(SHOP_ID)).value
+    return ''
+}
+
 export function clearAuthInfo() {
-    // const userStore = useUserStore()
-    // const tabsStore = useTabsStore()
-    // userStore.resetState()
-    // tabsStore.$reset()
-    // cache.remove(TOKEN_KEY)
-    // cache.remove("brandId")
-    // cache.remove("houseId")
-    // cache.remove("userId")
-    // resetRouter()
-    console.warn("***clearAuthInfo***")
+    cache.remove(TOKEN_KEY)
+    window.localStorage.removeItem("like_admin_token")
+    window.localStorage.removeItem("like_admin_brandId")
+    window.localStorage.removeItem("like_admin_userId")
+    window.localStorage.removeItem("like_admin_houseId")
+    cache.remove(SHOP_ID)
     // 确认窗体
-    ElMessageBox.confirm("已经在其他地方登录", '温馨提示', {
+    /*ElMessageBox.confirm("已经在其他地方登录", '温馨提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
         type: 'warning'
     }).then(() => {
         window.close();
-    })
+    })*/
 }

+ 10 - 9
src/utils/request/index.ts

@@ -1,14 +1,12 @@
-import { merge } from 'lodash'
+import {merge} from 'lodash'
 import configs from '@/config'
-import { Axios } from './axios'
-import { ContentTypeEnum, RequestCodeEnum, RequestMethodsEnum } from '@/enums/requestEnums'
-import type { AxiosHooks } from './type'
-import { clearAuthInfo, getToken,getUserId,getBrandId,getHouseId } from '../auth'
+import {Axios} from './axios'
+import {ContentTypeEnum, RequestCodeEnum, RequestMethodsEnum} from '@/enums/requestEnums'
+import type {AxiosHooks} from './type'
+import {clearAuthInfo, getBrandId, getHouseId, getShopId, getToken, getUserId} from '../auth'
 import feedback from '../feedback'
 import NProgress from 'nprogress'
-import { AxiosError, type AxiosRequestConfig } from 'axios'
-import router from '@/router'
-import { PageEnum } from '@/enums/pageEnum'
+import {AxiosError, type AxiosRequestConfig} from 'axios'
 
 // 处理axios的钩子函数
 const axiosHooks: AxiosHooks = {
@@ -20,6 +18,7 @@ const axiosHooks: AxiosHooks = {
         const userId = getUserId();
         const brandId = getBrandId();
         const houseId = getHouseId();
+        const shopId = getShopId();
         headers['userId'] = userId || ""
         headers['brandId'] = brandId || ""
         headers['houseId'] = houseId || ""
@@ -38,6 +37,7 @@ const axiosHooks: AxiosHooks = {
             config.data = params
             config.data.brandId = brandId
             config.data.houseId = houseId
+            config.data.shopId = shopId
             config.params = {}
         }
         // 如果是GET请求,将brandId和houseId添加到params中
@@ -45,7 +45,8 @@ const axiosHooks: AxiosHooks = {
             config.params = {
                 ...config.params,
                 brandId: brandId,
-                houseId: houseId
+                houseId: houseId,
+                shopId: shopId
             }
         }
         config.headers = headers

+ 192 - 131
src/views/account/login.vue

@@ -1,83 +1,86 @@
 <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";
+import {clearAuthInfo} from "@/utils/auth";
+
 const passwordRef = shallowRef<InputInstance>()
 const formRef = shallowRef<FormInstance>()
 const appStore = useAppStore()
@@ -86,89 +89,147 @@ 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)
+    window.localStorage.setItem("like_admin_houseId", currentRow.value.houseId)
+    config.value.webName = currentRow.name
+    if(currentRow.image){
+      config.value.webLogo = currentRow.image
+    }
+    const {
+      query: {redirect}
+    } = route
+    const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX
+    router.push(path)
+  }
 }
 // 回车按键监听
 const handleEnter = () => {
-    if (!formData.password) {
-        return passwordRef.value?.focus()
+  if (!formData.password) {
+    return passwordRef.value?.focus()
+  }
+  handleLogin()
+}
+const handleShopConfig = (params: any) => {
+  getShopConfigList({"contactTel": formData.account, houseIds: params}).then((res) => {
+    if (res && res.length > 0) {
+      if (res.length == 1) {
+        cache.set(SHOP_ID, res[0].id)
+        window.localStorage.setItem("like_admin_houseId",res[0].houseId)
+        config.value.webName = res[0].name
+        if(res[0].image){
+          config.value.webLogo = res[0].image
+        }
+        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,
+            houseId: item.houseId,
+            image: item.image
+          }
+        })
+      }
+    } else {
+      clearAuthInfo()
+      router.push(PageEnum.ERROR_403)
     }
-    handleLogin()
+  })
 }
 // 登录处理
 const handleLogin = async () => {
-    await formRef.value?.validate()
-    // 记住账号,缓存
-    cache.set(ACCOUNT_KEY, {
-        remember: remAccount.value,
-        account: remAccount.value ? formData.account : ''
-    })
-    try {
-        await userStore.login(formData)
-    } 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).then((res: any) => {
+      if(res.type === 1){
+        clearAuthInfo()
+        router.push(PageEnum.ERROR_403)
+      } else {
+        const houseIds = res.houseList.map((item: any) => item.houseId)
+        handleShopConfig(houseIds)
+      }
+    })
+  } catch (error) {
+    // getLoginCaptcha()
+  }
+
+  /*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>

+ 3 - 3
src/views/dish/lists/index.vue

@@ -88,7 +88,7 @@
                     min-width="150"
                     show-tooltip-when-overflow
                 />
-                <el-table-column label="状态" min-width="100">
+                <el-table-column label="状态" min-width="90">
                     <template #default="{ row }">
                         <el-switch
                             v-model="row.isShow"
@@ -98,8 +98,8 @@
                         />
                     </template>
                 </el-table-column>
-                <el-table-column label="排序" prop="sort" min-width="100" />
-                <el-table-column label="添加时间" prop="createTime" min-width="120" />
+                <el-table-column label="排序" prop="sort" min-width="80" />
+                <el-table-column label="添加时间" prop="createTime" min-width="170" />
                 <el-table-column label="操作" width="120" fixed="right">
                     <template #default="{ row }">
                         <el-button v-perms="['dish:edit', 'dish:add/edit']" type="primary" link>

+ 10 - 5
src/views/error/403.vue

@@ -1,12 +1,12 @@
 <template>
     <div class="error404">
-        <!-- <error code="403" title="您的账号权限不足,请联系管理员添加权限!" :show-btn="false">
+         <error code="403" title="您的账号权限不足,请联系管理员添加权限!" :show-btn="false">
             <template #content>
                 <div class="flex justify-center">
                     <img class="w-[150px] h-[150px]" src="@/assets/images/no_perms.png" alt="" />
                 </div>
             </template>
-        </error> -->
+        </error>
     </div>
 </template>
 
@@ -14,6 +14,9 @@
 import Error from './components/error.vue'
 import { onMounted } from 'vue'
 import { useRoute } from 'vue-router'
+import {PageEnum} from "@/enums/pageEnum"
+import {clearAuthInfo} from "@/utils/auth";
+const router = useRouter()
 
 const route = useRoute()
 
@@ -26,13 +29,15 @@ onMounted(() => {
     if (redirectUrl) {
         try {
             const url = new URL(decodeURIComponent(redirectUrl))
-            // const isAllowed = allowedDomains.some((domain: string) => 
+            // const isAllowed = allowedDomains.some((domain: string) =>
             //     url.hostname.endsWith(domain)
             // )
-            
+
             if (url) {
                 setTimeout(() => {
-                    window.location.href = url.toString()
+                    // window.location.href = url.toString()
+                  clearAuthInfo()
+                  router.push(PageEnum.LOGIN)
                 }, 1500)
             } else {
                 console.error(`不安全的跳转地址:`, redirectUrl)

+ 93 - 0
src/views/goods/category/edit.vue

@@ -0,0 +1,93 @@
+<template>
+  <div class="edit-popup">
+    <popup
+        ref="popupRef"
+        :title="popupTitle"
+        :async="true"
+        width="550px"
+        @confirm="handleSubmit"
+        @close="handleClose"
+    >
+      <el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
+        <el-form-item label="分类名称" prop="name">
+          <el-input v-model="formData.name" placeholder="请输入分类名称" clearable maxlength="10"/>
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <div>
+            <el-input-number v-model="formData.sort" :min="0" :max="9999"/>
+            <div class="form-tips">默认为0, 数值越大越排前</div>
+          </div>
+        </el-form-item>
+        <el-form-item label="日期预定" prop="choseDateState">
+          <el-switch v-model="formData.choseDateState" :active-value="1" :inactive-value="0"
+                     :disabled="mode === 'edit'"/>
+        </el-form-item>
+<!--        <el-form-item label="状态" prop="isShow">-->
+<!--          <el-switch v-model="formData.isShow" :active-value="1" :inactive-value="0"/>-->
+<!--        </el-form-item>-->
+      </el-form>
+    </popup>
+  </div>
+</template>
+<script lang="ts" setup>
+import type {FormInstance} from 'element-plus'
+import {goodsCategoryAdd, goodsCategoryEdit} from '@/api/goods/category'
+import Popup from '@/components/popup/index.vue'
+import feedback from '@/utils/feedback'
+
+const emit = defineEmits(['success', 'close'])
+const formRef = shallowRef<FormInstance>()
+const popupRef = shallowRef<InstanceType<typeof Popup>>()
+const mode = ref('add')
+const popupTitle = computed(() => {
+  return mode.value == 'edit' ? '编辑分类' : '新增分类'
+})
+const formData = reactive({
+  id: '',
+  name: '',
+  sort: 0,
+  isShow: 1,
+  choseDateState: 0
+})
+
+const formRules = {
+  name: [
+    {
+      required: true,
+      message: '请输入栏目名称',
+      trigger: ['blur']
+    }
+  ]
+}
+
+const handleSubmit = async () => {
+  await formRef.value?.validate()
+  mode.value == 'edit' ? await goodsCategoryEdit(formData) : await goodsCategoryAdd(formData)
+  feedback.msgSuccess('操作成功')
+  popupRef.value?.close()
+  emit('success')
+}
+
+const open = (type = 'add') => {
+  mode.value = type
+  popupRef.value?.open()
+}
+
+const setFormData = (data: Record<any, any>) => {
+  for (const key in formData) {
+    if (data[key] != null && data[key] != undefined) {
+      //@ts-ignore
+      formData[key] = data[key]
+    }
+  }
+}
+
+const handleClose = () => {
+  emit('close')
+}
+
+defineExpose({
+  open,
+  setFormData
+})
+</script>

+ 104 - 0
src/views/goods/category/index.vue

@@ -0,0 +1,104 @@
+<template>
+  <div>
+    <el-card class="!border-none mt-4" shadow="never" v-loading="pager.loading">
+      <div>
+        <el-button v-perms="['goods:category:add']" type="primary" @click="handleAdd()">
+          <template #icon>
+            <icon name="el-icon-Plus"/>
+          </template>
+          新增
+        </el-button>
+      </div>
+      <el-table class="mt-4" size="large" :data="pager.lists">
+        <el-table-column type="selection" width="55"/>
+        <el-table-column
+            label="分类名称"
+            prop="name"
+            min-width="120"
+            show-tooltip-when-overflow
+        />
+        <el-table-column label="商品数" prop="number" min-width="120"/>
+<!--        <el-table-column label="状态" min-width="120">-->
+<!--          <template #default="{ row }">-->
+<!--            <el-switch-->
+<!--                v-perms="['article:cate:change']"-->
+<!--                v-model="row.isShow"-->
+<!--                :active-value="1"-->
+<!--                :inactive-value="0"-->
+<!--                @change="changeStatus(row.id, row.isShow)"-->
+<!--            />-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <el-table-column label="排序" prop="sort" min-width="120"/>
+        <el-table-column label="操作" width="120" fixed="right">
+          <template #default="{ row }">
+            <el-button
+                v-perms="['goods:category:edit']"
+                type="primary"
+                link
+                @click="handleEdit(row)"
+            >
+              编辑
+            </el-button>
+            <el-button
+                v-perms="['goods:category:delete']"
+                type="danger"
+                link
+                @click="handleDelete(row.id)"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="flex justify-end mt-4">
+        <pagination v-model="pager" @change="getLists"/>
+      </div>
+    </el-card>
+    <edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false"/>
+  </div>
+</template>
+<script lang="ts" setup name="articleColumn">
+import {usePaging} from '@/hooks/usePaging'
+import feedback from '@/utils/feedback'
+import EditPopup from './edit.vue'
+import {goodsCategoryDelete, goodsCategoryEdit, goodsCategoryPage} from "@/api/goods/category";
+
+const editRef = shallowRef<InstanceType<typeof EditPopup>>()
+const showEdit = ref(false)
+
+const {pager, getLists} = usePaging({
+  fetchFun: goodsCategoryPage
+})
+const handleAdd = async () => {
+  showEdit.value = true
+  await nextTick()
+  editRef.value?.open('add')
+}
+
+const handleEdit = async (data: any) => {
+  showEdit.value = true
+  await nextTick()
+  editRef.value?.open('edit')
+  editRef.value?.setFormData(data)
+}
+
+const handleDelete = async (id: number) => {
+  await feedback.confirm('确定要删除?')
+  await goodsCategoryDelete({id, isDelete: 1})
+  feedback.msgSuccess('删除成功')
+  getLists()
+}
+
+const changeStatus = async (id: number, isShow: number) => {
+  try {
+    await goodsCategoryEdit({id, isShow})
+    feedback.msgSuccess('修改成功')
+    getLists()
+  } catch (error) {
+    getLists()
+  }
+}
+
+getLists()
+</script>

+ 443 - 0
src/views/goods/list/edit.vue

@@ -0,0 +1,443 @@
+<template>
+  <div class="article-edit">
+    <el-card class="!border-none" shadow="never">
+      <el-page-header content="商品编辑" @back="$router.back()"/>
+    </el-card>
+    <el-card class="mt-4 !border-none" shadow="never">
+      <el-form
+          ref="formRef"
+          class="ls-form"
+          :inline="true"
+          :model="formData"
+          label-width="100px"
+          :rules="rules"
+      >
+        <el-divider content-position="left"><span style="font-size: 18px">基础信息</span></el-divider>
+        <div class="xl:flex">
+          <div>
+            <el-form-item label="商品名称" prop="title">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.title"
+                    placeholder="请输入商品名称"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品分类" prop="title">
+              <div class="w-32vw">
+                <el-select class="w-[100%]" v-model="formData.productCategoryId" @change="handleCategory">
+                  <el-option label="全部" value/>
+                  <el-option
+                      v-for="item in optionsData.goodsCategory"
+                      :key="item.id"
+                      :label="item.name"
+                      :value="item.id"
+                  />
+                </el-select>
+              </div>
+            </el-form-item>
+            <el-form-item label="商品售价" prop="price">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.price"
+                    placeholder="请输入商品售价"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="划线价格" prop="originalPrice">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.originalPrice"
+                    placeholder="请输入划线价格"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品库存" prop="stock">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.stock"
+                    placeholder="请输入商品库存"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品排序" prop="sort">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.sort"
+                    placeholder="请输入商品排序"
+                    show-word-limit
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品单位" prop="unit">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.unit"
+                    placeholder="请输入商品单位"
+                    show-word-limit
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品标签" prop="tags">
+              <div class="w-32vw">
+                <el-select
+                    style="width: 100%"
+                    v-model="formData.tags"
+                    multiple
+                    filterable
+                    allow-create
+                    default-first-option
+                    placeholder="选择或创建商品标签">
+                  <el-option
+                      v-for="item in goodsTagOption"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value">
+                  </el-option>
+                </el-select>
+              </div>
+            </el-form-item>
+            <el-form-item label="购买须知" prop="needKnown">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.needKnown"
+                    placeholder="请输入购买须知"
+                    show-word-limit
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品保障" prop="guarantee">
+              <div class="w-32vw">
+                <el-input
+                    v-model="formData.guarantee"
+                    placeholder="请输入商品保障"
+                    show-word-limit
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="可入住日期" v-if="showDateRange">
+              <div class="w-32vw">
+                <el-date-picker
+                  v-model="selectedDates"
+                  type="dates"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  placeholder="选择一个或多个日期"
+                  style="width: 100%; margin-bottom: 10px"
+                />
+                <div v-if="selectedDates.length > 0" class="selected-dates">
+                  <div class="date-tag" v-for="(date, index) in processedDates" :key="index">
+                    {{ date }}
+                    <el-icon @click="removeDate(date)" style="cursor: pointer; margin-left: 5px;"><Close /></el-icon>
+                  </div>
+                </div>
+              </div>
+            </el-form-item>
+          </div>
+        </div>
+        <el-divider content-position="left"><span style="font-size: 18px">详细信息</span></el-divider>
+        <div class="xl:flex">
+          <div>
+            <el-form-item label="商品主图" prop="image">
+              <div class="w-32vw">
+                <material-picker v-model="formData.image" :limit="1"/>
+              </div>
+            </el-form-item>
+            <el-form-item label="商品视频" prop="video">
+              <div class="w-32vw">
+                <material-picker v-model="formData.video" type="video" :limit="1"/>
+              </div>
+            </el-form-item>
+            <el-form-item label="商品轮播图" prop="bannerImages">
+              <div class="w-32vw">
+                <material-picker v-model="formData.bannerImages" :limit="3"/>
+              </div>
+            </el-form-item>
+          </div>
+        </div>
+        <div class="xl:flex">
+<!--          <el-form-item label="商品详情" prop="detail">-->
+<!--            <div style="width: 100%">-->
+<!--              <editor v-model="formData.detail" :height="500"/>-->
+<!--            </div>-->
+<!--          </el-form-item>-->
+          <el-form-item label="商品详情图" prop="detailImages">
+            <div style="width: 100%">
+              <material-picker v-model="formData.detailImages" :limit="20"/>
+            </div>
+          </el-form-item>
+        </div>
+        <!--<el-divider content-position="left"><span style="font-size: 18px">其他</span></el-divider>
+        <div class="xl:flex">
+          <div>
+            <el-form-item label="赠送优惠券" prop="title">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.summary"
+                    :precision="2"
+                    :min="0.01"
+                    controls-position="right"
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="已售数量" prop="saleNum">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.saleNum"
+                    :precision="2"
+                    :min="0.01"
+                    controls-position="right"
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="商品推荐" prop="recommndType">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.recommndType"
+                    :precision="2"
+                    :min="0.01"
+                    controls-position="right"
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="会员专属" prop="onlyMember">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.onlyMember"
+                    :precision="2"
+                    :min="0.01"
+                    controls-position="right"
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="买就送" prop="buyToGift">
+              <div class="w-32vw">
+                <el-input-number
+                    v-model="formData.buyToGift"
+                    :precision="2"
+                    :min="0.01"
+                    controls-position="right"
+                />
+              </div>
+            </el-form-item>
+          </div>
+        </div>-->
+      </el-form>
+    </el-card>
+    <footer-btns>
+      <el-button type="primary" @click="handleSave">保存</el-button>
+    </footer-btns>
+  </div>
+</template>
+
+<script lang="ts" setup name="articleListsEdit">
+import type {FormInstance} from 'element-plus'
+import feedback from '@/utils/feedback'
+import {useDictOptions} from '@/hooks/useDictOptions'
+import useMultipleTabs from '@/hooks/useMultipleTabs'
+import Editor from '@/components/editor/index.vue'
+import {goodsCategoryPage} from "@/api/goods/category";
+import {goodsEdit, goodsDetail} from "@/api/goods/list";
+import { getShopId } from '@/utils/auth'
+import { Close } from '@element-plus/icons-vue'
+
+const route = useRoute()
+const router = useRouter()
+const formData = reactive<any>({
+  id: null,
+  title: '',
+  productCategoryId: null,
+  price: null,
+  originalPrice: null,
+  stock: 0,
+  sort: 0,
+  unit: 0,
+  tags: 0,
+  isShow: 1,
+  needKnown: null,
+  guarantee: null,
+  image: '',
+  mainResourceList: null,
+  video: '',
+  detail: '',
+  useDates: '',
+  shopId: getShopId()
+})
+const goodsTagOption = [{
+  value: '日用品',
+  label: '日用品'
+}]
+
+const {optionsData} = useDictOptions<{
+  goodsCategory: any[]
+}>({
+  goodsCategory: {
+    api: goodsCategoryPage,
+    params: {pageNo: 1, pageSize: 100},
+    transformData(data: any) {
+      return data.lists
+    }
+  }
+})
+
+const {removeTab} = useMultipleTabs()
+const formRef = shallowRef<FormInstance>()
+const rules = reactive({
+  title: [{required: true, message: '请输入商品名称', trigger: 'blur'}],
+  cid: [{required: true, message: '请选择商品分类', trigger: 'blur'}],
+  summary: [{required: true, message: '请输入价格', trigger: 'blur'}],
+  image: [{required: true, message: '添加商品图片', trigger: 'change'}]
+})
+
+const selectedDates = ref<string[]>([])
+const showDateRange = ref(false)
+
+// 计算处理后的所有日期(包括单个日期和日期范围)
+const processedDates = computed(() => {
+  const dates = [...selectedDates.value]
+  return dates.sort()
+})
+
+// 移除日期
+const removeDate = (date: string) => {
+  const index = selectedDates.value.indexOf(date)
+  if (index > -1) {
+    selectedDates.value.splice(index, 1)
+  }
+}
+
+// 在保存时将日期数据加入formData
+const handleSave = async () => {
+  await formRef.value?.validate()
+
+  const submitData = {
+    ...formData,
+    availableDates: processedDates.value // 添加可入住日期数据
+  }
+
+  // 构建主资源列表(包括轮播图和详情图)
+  const mainResourceList: any[] = [];
+
+  if (formData.bannerImages) {
+    formData.bannerImages.forEach((item: any, index: number) => {
+      mainResourceList.push({
+        resourceType: 1, // 1轮播图
+        resourceName: `轮播图${index + 1}`,
+        resourceUrl: item,
+        sort: index + 1
+      });
+    });
+  }
+
+  if (formData.detailImages) {
+    formData.detailImages.forEach((item: any, index: number) => {
+      mainResourceList.push({
+        resourceType: 2, // 2详情图
+        resourceName: `详情图${index + 1}`,
+        resourceUrl: item,
+        sort: index + 1
+      });
+    });
+  }
+
+  submitData.mainResourceList = mainResourceList;
+  if(formData.tags){
+    submitData.tags = formData.tags.join(',')
+  }
+  if(selectedDates.value.length > 0){
+    const dates = [...selectedDates.value]
+    // 使用日期排序而不是字符串排序
+    const sortedDates = dates.sort((a, b) => new Date(a).getTime() - new Date(b).getTime())
+    submitData.startDate = sortedDates[0]
+    submitData.endDate = sortedDates[selectedDates.value.length - 1]
+    submitData.useDates = sortedDates.join(',')
+  }
+  feedback.msgSuccess('操作成功')
+  if (route.query.id) {
+    await goodsEdit(submitData)
+  } else {
+    await goodsEdit(submitData)
+  }
+  feedback.msgSuccess('操作成功')
+  removeTab()
+  router.back()
+}
+
+const handleCategory = (val:any) => {
+  const selectedCategory = optionsData.goodsCategory.find((item: any) => item.id === val);
+  showDateRange.value = false
+  selectedDates.value = []
+  if(selectedCategory && selectedCategory.choseDateState === 1){
+    showDateRange.value = true
+  }
+}
+
+// 在获取详情时处理日期数据
+const getDetails = async () => {
+  const data = await goodsDetail({
+    id: route.query.id
+  })
+  Object.keys(formData).forEach((key) => {
+    //@ts-ignore
+    formData[key] = data[key];
+    if (key == 'summary') {
+      formData[key] = Number(formData[key])
+    }
+    if(key === 'video' && !data['video']){
+      formData[key] = ''
+    }
+    if(key === 'mainResourceList' && data['mainResourceList']){
+      formData.bannerImages = data['mainResourceList'].filter((item:any) => item.resourceType === 1).map((item:any) => {
+        return item.resourceUrl
+      })
+      formData.detailImages = data['mainResourceList'].filter((item:any) => item.resourceType === 2).map((item:any) => {
+        return item.resourceUrl
+      })
+    }
+    if(key === 'tags' && data['tags']){
+      formData[key] = data[key].split(',')
+    }
+    console.log(key,data[key])
+    if(key === 'useDates' && data['useDates']){
+      console.log('显示 日期')
+      showDateRange.value = true
+      selectedDates.value = data['useDates'].split(',')
+    }
+  })
+}
+
+route.query.id && getDetails()
+
+</script>
+<style>
+.w-32vw {
+  width: 32vw;
+}
+
+.selected-dates {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-top: 10px;
+}
+
+.date-tag {
+  background-color: #ecf5ff;
+  border: 1px solid #d9ecff;
+  border-radius: 4px;
+  padding: 4px 8px;
+  display: flex;
+  align-items: center;
+  font-size: 12px;
+}
+</style>

+ 185 - 0
src/views/goods/list/index.vue

@@ -0,0 +1,185 @@
+<template>
+  <div class="article-lists" v-perms="['goods:list:query']">
+    <el-card class="!border-none" shadow="never">
+      <el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
+        <el-form-item label="商品名称">
+          <el-input
+              class="w-[280px]"
+              v-model="queryParams.title"
+              clearable
+              @keyup.enter="resetPage"
+          />
+        </el-form-item>
+        <el-form-item label="商品分类">
+          <el-select class="w-[280px]" v-model="queryParams.categoryId">
+            <el-option label="全部" value/>
+            <el-option
+                v-for="item in optionsData.goodsCategory"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="商品状态">
+          <el-select class="w-[280px]" v-model="queryParams.auditStatus">
+            <el-option label="全部" value/>
+            <el-option label="待审核" :value="0"/>
+            <el-option label="已通过" :value="1"/>
+            <el-option label="已驳回" :value="2"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="resetPage">查询</el-button>
+          <el-button @click="resetParams">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card class="!border-none mt-4" shadow="never">
+      <div>
+        <router-link v-perms="['goods:list:add', 'goods:list:add/edit']" :to="{ path: getRoutePath('goods:list:add/edit') }">
+          <el-button class="mr-3" type="primary">
+            <template #icon>
+              <icon name="el-icon-Plus"/>
+            </template>
+            添加商品
+          </el-button>
+        </router-link>
+        <!-- <multi-del-btn></multi-del-btn> -->
+      </div>
+      <el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
+        <el-table-column label="ID" type="index" min-width="80"/>
+        <el-table-column label="图片" min-width="100">
+          <template #default="{ row }">
+            <image-contain
+                v-if="row.image"
+                :src="row.image"
+                :width="60"
+                :height="45"
+                :preview-src-list="[row.image]"
+                preview-teleported
+                fit="contain"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+            label="商品名称"
+            prop="title"
+            min-width="160"
+            show-tooltip-when-overflow
+        />
+        <el-table-column label="商品分类" prop="categoryName" min-width="150" show-tooltip-when-overflow/>
+        <el-table-column label="售价/元" prop="price" min-width="70"/>
+        <el-table-column
+            label="审核状态"
+            prop="auditStatus"
+            min-width="100"
+            show-tooltip-when-overflow
+        >
+          <template #default="{ row }">
+            <span v-if="row.auditStatus === 0" class="text-yellow-500">待审核</span>
+            <span v-else-if="row.auditStatus === 1" class="text-green-500">已通过</span>
+            <span v-else-if="row.auditStatus === 2" class="text-red-500">已驳回</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+            label="库存"
+            prop="stock"
+            min-width="100"
+            show-tooltip-when-overflow
+        />
+        <el-table-column label="排序" prop="sort" min-width="80"/>
+        <el-table-column label="添加时间" prop="createTime" min-width="120"/>
+        <el-table-column label="操作" width="120" fixed="right">
+          <template #default="{ row }">
+            <el-button v-perms="['goods:list:edit', 'goods:list:add/edit']" type="primary" link>
+              <router-link :to="{ path: getRoutePath('goods:list:add/edit'), query: { id: row.id } }">
+                编辑
+              </router-link>
+            </el-button>
+            <el-button
+                v-perms="['goods:list:delete']"
+                type="danger"
+                link
+                @click="handleDelete(row.id)"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="flex justify-end mt-4">
+        <pagination v-model="pager" @change="getLists"/>
+      </div>
+    </el-card>
+  </div>
+</template>
+<script lang="ts" setup name="goodsPage">
+import {goodsPage} from '@/api/goods/list'
+import {goodsCategoryPage} from '@/api/goods/category'
+import {useDictOptions} from '@/hooks/useDictOptions'
+import {usePaging} from '@/hooks/usePaging'
+import {getRoutePath} from '@/router'
+import { getShopId } from '@/utils/auth'
+import feedback from '@/utils/feedback'
+
+const queryParams = reactive({
+  title: '',
+  cid: '',
+  isShow: '',
+  shopId: getShopId()
+})
+const {pager, getLists, resetPage, resetParams} = usePaging({
+  fetchFun: goodsPage,
+  params: queryParams
+})
+
+const {optionsData} = useDictOptions<{
+  goodsCategory: any[]
+}>({
+  goodsCategory: {
+    api: goodsCategoryPage,
+    params: {pageNo: 1, pageSize: 100},
+    transformData(data: any) {
+      return data.lists
+    }
+  }
+})
+
+const handleDelete = async (id: number) => {
+  await feedback.confirm('确定要删除?')
+  // await goodsEdit({id})
+  feedback.msgSuccess('删除成功')
+  getLists()
+}
+
+onActivated(() => {
+  getLists()
+})
+
+getLists()
+</script>
+<style lang="scss" scoped>
+.remark-text {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+  line-height: 1.5;
+  max-height: 3em; // 2行的高度
+}
+
+.text-yellow-500 {
+  color: #f59e0b;
+}
+
+.text-red-500 {
+  color: #ef4444;
+}
+
+.text-green-500 {
+  color: #10b981;
+}
+</style>

+ 4 - 4
src/views/material/index.vue

@@ -29,10 +29,10 @@ const tabsMap = [
         type: 'image',
         name: '图片'
     },
-    // {
-    //     type: 'video',
-    //     name: '视频'
-    // }
+    {
+        type: 'video',
+        name: '视频'
+    }
 ]
 const activeTab = ref('image')
 </script>

+ 51 - 14
src/views/order/console.vue

@@ -675,22 +675,59 @@ const confirmBalancePayment = () => {
 
   feedback.loading('正在处理余额支付...')
 
-  orderPay({ oid: params.number, code: balancePayCode.value })
-      .then((res) => {
-        console.log(res)
-        // 实际上支付成功之后,res返回的是[],如果不是实时成功,返回的是个对象, 形如:{orderId: '123456789', sn: '7895004131583689'}
-        if (res == null || res.length == 0) {
+  getUserIdByMobile({
+    mobile: balancePaymentPhone.value,
+    terminal: 1
+  }).then((response) => {
+    console.log("**getUserIdByMobile**", response)
+    const userIdByMobile = response.success && response.single ? response.single.id : null
+    queryUserMemberInfo({
+      userId: userIdByMobile,
+    }).then((res) => {
+      console.log("**queryUserMemberInfo**", res)
+      // 假设返回的数据结构中有 accountAmount 字段表示余额
+      if (res && res.success && res.single) {
+        balanceAmount.value = res.single.accountAmount || null
+        balancePayCode.value = res.single.payCode
+
+        if (!balanceAmount.value || balanceAmount.value < 0) {
+          feedback.msgError('暂无余额')
           feedback.closeLoading()
-          feedback.notifySuccess('余额结账成功' + orderData.payAmount + '元')
-          balancePaymentDialogVisible.value = false
-          showOrderConsole.value = false
-          emit('init')
+          return
         }
-      })
-      .catch((e) => {
-        console.log('=====---', e)
-        feedback.closeLoading()
-      })
+        if (balanceAmount.value && balanceAmount.value == 0) {
+          feedback.msgError('余额不足')
+          feedback.closeLoading()
+          return
+        }
+        orderPay({ oid: params.number, code: balancePayCode.value })
+            .then((res) => {
+              console.log(res)
+              // 实际上支付成功之后,res返回的是[],如果不是实时成功,返回的是个对象, 形如:{orderId: '123456789', sn: '7895004131583689'}
+              if (res == null || res.length == 0) {
+                feedback.closeLoading()
+                feedback.notifySuccess('余额结账成功' + orderData.payAmount + '元')
+                balancePaymentDialogVisible.value = false
+                showOrderConsole.value = false
+                emit('init')
+              }
+            })
+            .catch((e) => {
+              console.log('=====---', e)
+              feedback.closeLoading()
+            })
+      }
+    }).catch((error) => {
+      console.error('获取余额失败:', error)
+      balanceAmount.value = '-1'
+      balancePayCode.value = ''
+      feedback.msgError('获取余额失败')
+      feedback.closeLoading()
+    })
+  }).catch((error) => {
+    feedback.msgError('手机号查询失败')
+    feedback.closeLoading()
+  })
 }
 
 // 添加扫码事件监听函数

+ 15 - 4
src/views/orders/list.vue

@@ -102,7 +102,7 @@
                 <el-table-column
                     label="下单时间"
                     prop="checkoutTime"
-                    min-width="120"
+                    min-width="130"
                 ></el-table-column>
                 <el-table-column
                     label="订单号"
@@ -113,7 +113,7 @@
                 <el-table-column
                     label="类型"
                     prop="type"
-                    :formatter="(row: any) => (row.type == 0 ? '吧台点单' : '扫码点单')"
+                    :formatter="(row: any) => (row.type == 0 ? '吧台点单' : row.type == 1 ? '扫码点单' : '在线购物')"
                 ></el-table-column>
                 <el-table-column label="桌号/餐号" prop="deskName">
                     <template #default="{ row }">{{
@@ -179,7 +179,13 @@
                                     ? '退款中'
                                     : row.status == 3
                                     ? '支付失败'
-                                    : '已关闭'
+                                    : row.status == 6
+                                    ? '已关闭'
+                                    : row.status == 7
+                                    ? '部分核销'
+                                    : row.status == 8
+                                    ? '已核销'
+                                    : '未知'
                             }}
                             <div v-if="row.refundStatus == 'SUCCESS'" class="refund-info">
                                 <div>退款时间:{{ row.refundTime }}</div>
@@ -212,7 +218,7 @@
             @close="refundDialogVisible = false"
         >
             <div class="refund-dialog-content">
-                <el-input v-model="refundAmount" placeholder="请输入退款金额" type="number">
+                <el-input v-model="refundAmount" placeholder="请输入退款金额" type="number" :disabled="refundAmountDisabled">
                     <template #prepend><icon :size="25" name="el-icon-money" /></template>
                     <template #append>元</template>
                 </el-input>
@@ -315,6 +321,7 @@ const handleExpandChange = (row: any, expandedRows: any) => {
 const refundDialogVisible = ref(false)
 const refundAmount = ref('')
 const payMethod = ref('')
+const refundAmountDisabled = ref(true)
 let refundOrder: {
     refundTime: string
     refundAmount: number
@@ -329,7 +336,11 @@ const refundLoading = ref(false)
 const refund = async (row: any) => {
     refundOrder = row
     payMethod.value = row.payMethod
+    refundAmountDisabled.value = row.type === 2
     refundAmount.value = ''
+    if (row.type === 2) {
+      refundAmount.value = row.payAmount
+    }
     refundDialogVisible.value = true
 }
 

+ 188 - 210
src/views/shop/info.vue

@@ -1,236 +1,214 @@
 <!-- 网站信息 -->
 <template>
-    <div class="website-information">
+  <div class="website-information">
+    <div style="display: flex">
+      <div style="width: 50%;">
         <el-form ref="formRef" :model="formData" label-width="120px">
-            <el-card shadow="never" class="!border-none">
-                <div class="text-xl font-medium mb-[20px]">店铺设置</div>
-                <el-form-item label="店铺名称" prop="name">
-                    <div class="w-80">
-                        <el-input
-                            v-model="formData.name"
-                            placeholder="请输入店铺名称"
-                            maxlength="20"
-                            show-word-limit
-                        ></el-input>
-                    </div>
-                </el-form-item>
-                <el-form-item label="店铺简介" prop="intro">
-                    <div class="w-80">
-                        <el-input
-                            v-model="formData.intro"
-                            :rows="5"
-                            type="textarea"
-                            placeholder="请输入店铺介绍"
-                            maxlength="90"
-                            show-word-limit
-                        ></el-input>
-                    </div>
-                </el-form-item>
-                <el-form-item label="店铺公告" prop="notice">
-                    <div class="w-80">
-                        <el-input
-                            v-model="formData.notice"
-                            :rows="5"
-                            type="textarea"
-                            placeholder="请输入店铺公告"
-                            maxlength="100"
-                            show-word-limit
-                        ></el-input>
-                    </div>
-                </el-form-item>
-                <el-form-item label="店铺图片" prop="image">
-                    <div>
-                        <material-picker v-model="formData.image" :limit="1" />
-                        <div class="form-tips">建议尺寸:100*100像素,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item>
-                <el-form-item label="预支付" prop="prePay">
-                    <el-switch v-model="formData.prePay" :active-value="1" :inactive-value="0" />
-                </el-form-item>
-                <el-form-item label="店铺状态" prop="status">
-                    <el-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
-                </el-form-item>
-                <!-- <el-form-item label="网站logo" prop="logo">
-                    <div>
-                        <material-picker v-model="formData.logo" :limit="1" />
-                        <div class="form-tips">建议尺寸:200*200像素,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item>
-                <el-form-item label="登录页广告图" prop="backdrop">
-                    <div>
-                        <material-picker v-model="formData.backdrop" :limit="1" />
-                        <div class="form-tips">建议尺寸:400*400像素,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item> -->
-            </el-card>
-            <!-- <el-card shadow="never" class="!border-none mt-4">
-                <div class="text-xl font-medium mb-[20px]">前台设置</div>
-                <el-form-item label="商城名称" prop="shopName">
-                    <div class="w-80">
-                        <el-input
-                            v-model="formData.shopName"
-                            placeholder="请输入店铺/商城名称"
-                            maxlength="30"
-                            show-word-limit
-                        ></el-input>
-                    </div>
-                </el-form-item>
-                <el-form-item label="商城LOGO" prop="shopLogo">
-                    <div>
-                        <material-picker v-model="formData.shopLogo" :limit="1" />
-                        <div class="form-tips">建议尺寸:100*100px,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item>
-            </el-card>
-            <el-card shadow="never" class="!border-none mt-4">
-                <div class="text-xl font-medium mb-[20px]">PC端设置</div>
-                <el-form-item label="PC端LOGO" prop="pcLogo">
-                    <div>
-                        <material-picker v-model="formData.pcLogo" :limit="1" />
-                        <div class="form-tips">建议尺寸:120*28px,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item>
-                <el-form-item label="网站标题" prop="pcTitle">
-                    <div class="w-80">
-                        <el-input
-                            v-model.trim="formData.pcTitle"
-                            placeholder="请输入PC端网站标题"
-                            maxlength="30"
-                            show-word-limit
-                        />
-                    </div>
-                </el-form-item>
-                <el-form-item label="网站图标" prop="pcIco">
-                    <div>
-                        <material-picker v-model="formData.pcIco" :limit="1" />
-                        <div class="form-tips">建议尺寸:100*100像素,支持jpg,jpeg,png格式</div>
-                    </div>
-                </el-form-item>
-                <el-form-item label="网站描述" prop="pcDesc">
-                    <div class="w-80">
-                        <el-input v-model.trim="formData.pcDesc" placeholder="请输入PC端网站描述" />
-                    </div>
-                </el-form-item>
-                <el-form-item label="网站关键词" prop="pcKeywords">
-                    <div class="w-80">
-                        <el-input
-                            v-model.trim="formData.pcKeywords"
-                            placeholder="请输入PC端网站关键词"
-                        />
-                    </div>
-                </el-form-item>
-            </el-card> -->
+          <el-card shadow="never" class="!border-none">
+            <div class="text-xl font-medium mb-[20px]">店铺信息</div>
+            <el-form-item label="店铺名称" prop="name">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.name"
+                    placeholder="请输入店铺名称"
+                    maxlength="20"
+                    show-word-limit
+                ></el-input>
+              </div>
+            </el-form-item>
+            <el-form-item label="店铺简介" prop="intro">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.intro"
+                    :rows="5"
+                    type="textarea"
+                    placeholder="请输入店铺介绍"
+                    maxlength="90"
+                    show-word-limit
+                ></el-input>
+              </div>
+            </el-form-item>
+            <el-form-item label="店铺公告" prop="notice">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.notice"
+                    :rows="5"
+                    type="textarea"
+                    placeholder="请输入店铺公告"
+                    maxlength="100"
+                    show-word-limit
+                ></el-input>
+              </div>
+            </el-form-item>
+            <el-form-item label="店铺图片" prop="image">
+              <div>
+                <material-picker v-model="formData.image" :limit="1"/>
+                <div class="form-tips">建议尺寸:100*100像素,支持jpg,jpeg,png格式</div>
+              </div>
+            </el-form-item>
+            <el-form-item label="banner图片" prop="banner">
+              <div>
+                <material-picker v-model="formData.banner" :limit="3"/>
+                <div class="form-tips">建议尺寸:100*100像素,支持jpg,jpeg,png格式</div>
+              </div>
+            </el-form-item>
+<!--            <el-form-item label="预支付" prop="prePay">
+              <el-switch v-model="formData.prePay" :active-value="1" :inactive-value="0"/>
+            </el-form-item>-->
+          </el-card>
         </el-form>
-        <footer-btns v-perms="['setting:website:save']">
-            <el-button type="primary" @click="handleSubmit">保存</el-button>
-        </footer-btns>
+      </div>
+      <div style="width: 50%;">
+        <el-form label-width="120px">
+          <el-card shadow="never" class="!border-none">
+            <div class="text-xl font-medium mb-[20px]">&nbsp;</div>
+            <el-form-item label="联系人" prop="contactPsn">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.contactPsn"
+                    placeholder="请输入联系人"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="联系方式" prop="contactTel">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.contactTel"
+                    placeholder="请输入联系方式"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="身份证照">
+              <div style="display: flex">
+                <material-picker v-model="formData.idCardFront" :limit="1"/>
+                <material-picker v-model="formData.idCardBack" :limit="1"/>
+              </div>
+            </el-form-item>
+            <el-form-item label="资质证件">
+              <div style="display: flex">
+                <material-picker v-model="formData.businessLicense" :limit="1"/>
+                <material-picker v-model="formData.operatingLicense" :limit="1"/>
+              </div>
+            </el-form-item>
+            <el-form-item label="地址" prop="address">
+              <div class="w-80">
+                <el-input
+                    v-model="formData.address"
+                    placeholder="请输入地址"
+                    clearable
+                />
+              </div>
+            </el-form-item>
+            <el-form-item label="店铺状态" prop="status">
+              <el-switch v-model="formData.status" :active-value="1" :inactive-value="0"
+                         active-text="开始营业" inactive-text="暂停营业"/>
+            </el-form-item>
+          </el-card>
+        </el-form>
+      </div>
     </div>
+    <footer-btns v-perms="['setting:website:save']">
+      <el-button type="primary" @click="handleSubmit">保存</el-button>
+    </footer-btns>
+  </div>
 </template>
 
 <script lang="ts" setup name="webInformation">
-import { getShopConfig, saveShopConfig } from '@/api/shop'
+import {getShopConfig, saveShopConfig} from '@/api/shop'
 import feedback from '@/utils/feedback'
-import type { FormInstance } from 'element-plus'
+import type {FormInstance} from 'element-plus'
+import cache from "@/utils/cache";
+import {ACCOUNT_KEY, SHOP_ID} from "@/enums/cacheEnums";
+import useAppStore from "@/stores/modules/app";
+const appStore = useAppStore()
+const config = computed(() => appStore.config)
+
 const formRef = ref<FormInstance>()
 // 表单数据
 const formData = reactive({
-    id: '',
-    name: '', // 店铺名称
-    intro: '',
-    notice: '',
-    image: '',
-    status: '',
-    prePay: ''
+  id: null,
+  name: '', // 店铺名称
+  intro: '',
+  notice: '',
+  image: '',
+  status: '',
+  prePay: '',
+  banner: '',
+  contactPsn: '',
+  contactTel: '',
+  address: '',
+  idCardFront: '',
+  idCardBack: '',
+  businessLicense: '',
+  operatingLicense: '',
+  userRelationId: null,
 })
 
-// 表单验证
-// const rules = {
-//     name: [
-//         {
-//             required: true,
-//             message: '请输入网站名称',
-//             trigger: ['blur']
-//         }
-//     ],
-//     favicon: [
-//         {
-//             required: true,
-//             message: '请选择网站图标',
-//             trigger: ['change']
-//         }
-//     ],
-//     logo: [
-//         {
-//             required: true,
-//             message: '请选择网站logo',
-//             trigger: ['change']
-//         }
-//     ],
-//     backdrop: [
-//         {
-//             required: true,
-//             message: '请选择登录页广告图',
-//             trigger: ['change']
-//         }
-//     ],
-//     shopName: [
-//         {
-//             required: true,
-//             message: '请输入店铺/商城名称',
-//             trigger: ['blur']
-//         }
-//     ],
-//     shopLogo: [
-//         {
-//             required: true,
-//             message: '请选择商城LOGO',
-//             trigger: ['change']
-//         }
-//     ],
-//     pcLogo: [
-//         {
-//             required: true,
-//             message: '请选择PC端LOGO',
-//             trigger: ['change']
-//         }
-//     ],
-//     pcTitle: [
-//         {
-//             required: true,
-//             message: '请输入PC端网站标题',
-//             trigger: ['blur']
-//         }
-//     ],
-//     pcIco: [
-//         {
-//             required: true,
-//             message: '请选择PC端网站图标',
-//             trigger: ['change']
-//         }
-//     ]
-// }
-
 // 获取店铺信息
 const getData = async () => {
-    const data = await getShopConfig()
-    for (const key in formData) {
-        //@ts-ignore
-        formData[key] = data[key]
-    }
-    if(!formData.image){//不能是null,会报错
-        formData.image = '';
+  const shopId = cache.get(SHOP_ID);
+  let 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
+  }
+  const data = await getShopConfig(params)
+  for (const key in formData) {
+    //@ts-ignore
+    formData[key] = data[key]
+  }
+  formData.userRelationId = data?data['shopUserRelationId']:''
+  if (formData.banner) {
+    formData.banner = formData.banner.split(',')
+  } else {
+    formData.banner = '';
+  }
+  if (!formData.image) {//不能是null,会报错
+    formData.image = '';
+  }
+  if (!formData.idCardFront) {//不能是null,会报错
+    formData.idCardFront = '';
+  }
+  if (!formData.idCardBack) {//不能是null,会报错
+    formData.idCardBack = '';
+  }
+  if (!formData.businessLicense) {//不能是null,会报错
+    formData.businessLicense = '';
+  }
+  if (!formData.operatingLicense) {//不能是null,会报错
+    formData.operatingLicense = '';
+  }
+  cache.set(SHOP_ID, formData.id)
+  config.value.webName = formData.name
+  if(formData.image){
+    config.value.webLogo = formData.image
+  }
 }
 
 // 保存店铺信息
 const handleSubmit = async () => {
-    // await formRef.value?.validate()
-    await saveShopConfig(formData)
-    feedback.msgSuccess('操作成功')
-    getData()
+  console.log(formData)
+  if(formData.banner){
+    formData.banner = formData.banner.join(',')
+  }
+  await saveShopConfig(formData)
+  feedback.msgSuccess('操作成功')
+  getData()
 }
 
 getData()
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.website-information{
+  background: #fff;
+}
+</style>

+ 44 - 7
src/views/workbench/index.vue

@@ -156,9 +156,9 @@
 </template>
 
 <script lang="ts" setup name="workbench">
-import { getWorkbench } from '@/api/app'
 import vCharts from 'vue-echarts'
-import { SwitchButton } from '@element-plus/icons-vue'
+import {getWorkbench} from '@/api/app'
+import {SwitchButton} from '@element-plus/icons-vue'
 import menu_admin from './image/menu_admin.png'
 import menu_role from './image/menu_role.png'
 import menu_dept from './image/menu_dept.png'
@@ -169,7 +169,13 @@ import menu_auth from './image/menu_auth.png'
 import menu_web from './image/menu_web.png'
 import oa_code from './image/oa_code.png'
 import service_code from './image/service_code.png'
-import { getShopConfig, changeShopStatus, statisticsDishTop10 } from '@/api/shop'
+import {changeShopStatus, getShopConfig, statisticsDishTop10} from '@/api/shop'
+import cache from "@/utils/cache";
+import {ACCOUNT_KEY, SHOP_ID} from "@/enums/cacheEnums";
+import useAppStore from "@/stores/modules/app";
+const appStore = useAppStore()
+const config = computed(() => appStore.config)
+
 const activeIndex = ref(0)
 // 表单数据
 const workbenchData: any = reactive({
@@ -312,7 +318,9 @@ const workbenchData: any = reactive({
                             rankNo = 'no3'
                             break
                     }
-                    return `{${rankNo}|${index + 1}} {labelName|${value}}`
+                    // 限制显示字数为5个字符,超过用省略号
+                    const displayName = value.length > 5 ? value.substring(0, 5) + '...' : value
+                    return `{${rankNo}|${index + 1}} {labelName|${displayName}}`
                 },
                 align: 'left',
                 rich: {
@@ -346,6 +354,18 @@ const workbenchData: any = reactive({
                 }
             }
         },
+        tooltip: {
+            trigger: 'axis',
+            formatter: (params: any) => {
+                if (params && params.length > 0) {
+                    const dataIndex = params[0].dataIndex
+                    const originalName = workbenchData.listOption.yAxis.data[dataIndex]
+                    const value = params[0].value
+                    return `${originalName}: ${value}次`
+                }
+                return ''
+            }
+        },
         series: [
             {
                 // data: [33, 26, 25, 15, 12, 9, 9],
@@ -416,10 +436,29 @@ const getData = async () => {
     workbenchData.visitorOption.series[0].data = res.visitor.list
 }
 const shopInfo = () => {
-    getShopConfig().then((res) => {
+  const shopId = cache.get(SHOP_ID);
+  let 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(params).then((res) => {
         workbenchData.shopId = res.id
         workbenchData.shopName = res.name
         workbenchData.shopStatus = res.status
+        cache.set(SHOP_ID, res.id)
+      config.value.webName = res.name
+      if(res.image){
+        config.value.webLogo = res.image
+      }
+      getData()
+      dishTop10()
     })
 }
 const changeStatus = () => {
@@ -443,8 +482,6 @@ const dishTop10 = () => {
     })
 }
 shopInfo()
-getData()
-dishTop10()
 </script>
 
 <style lang="scss" scoped></style>