yb 10 сар өмнө
parent
commit
1094bb05aa

+ 4 - 4
.env.local

@@ -4,16 +4,16 @@ NODE_ENV=development
 VITE_DEV=true
 
 # 请求路径  远端, 本地
-VITE_BASE_URL='https://api.ifoodme.com'
-# VITE_BASE_URL='http://localhost:48081'
+# VITE_BASE_URL='https://api.ifoodme.com'
+VITE_BASE_URL='http://localhost:48081'
 
 # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
 VITE_UPLOAD_TYPE=server
 # 上传路径
 
 # 远端, 本地
-VITE_UPLOAD_URL='https://api.ifoodme.com/admin-api/infra/file/upload'
-# VITE_UPLOAD_URL='http://localhost:48081/admin-api/infra/file/upload'
+# VITE_UPLOAD_URL='https://api.ifoodme.com/admin-api/infra/file/upload'
+VITE_UPLOAD_URL='http://localhost:48081/admin-api/infra/file/upload'
 
 # 是否使用本地图片映射
 VITE_USE_LOCAL_IMAGES=true

+ 5 - 1
src/api/login/index.ts

@@ -1,6 +1,6 @@
 import request from '@/config/axios'
 import { getRefreshToken } from '@/utils/auth'
-import type { UserLoginVO } from './types'
+import type { UserLoginVO, UserRegisterVO } from './types'
 
 export interface SmsCodeVO {
   mobile: string
@@ -17,6 +17,10 @@ export const login = (data: UserLoginVO) => {
   return request.post({ url: '/system/auth/login', data })
 }
 
+export const register = (data: UserRegisterVO) => {
+  return request.post({ url: '/system/auth/register', data })
+}
+
 // 刷新访问令牌
 export const refreshToken = () => {
   return request.post({ url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken() })

+ 6 - 0
src/api/login/types.ts

@@ -7,6 +7,12 @@ export type UserLoginVO = {
   socialState?: string
 }
 
+export type UserRegisterVO = {
+  mobile: string
+  password: string
+  code: string
+}
+
 export type TokenType = {
   id: number // 编号
   accessToken: string // 访问令牌

+ 206 - 17
src/api/mall/order/storeOrder/index.ts

@@ -8,6 +8,8 @@ export interface StoreOrderVO {
   realName: string
   userPhone: string
   userAddress: string
+  createTime: any
+  dueTime: any
   cartId: string
   freightPrice: number
   totalNum: number
@@ -18,11 +20,11 @@ export interface StoreOrderVO {
   deductionPrice: number
   couponId: number
   couponPrice: number
-  paid: byte
+  paid: any
   payTime: Date
   payType: string
   status: boolean
-  refundStatus: byte
+  refundStatus: any
   refundReasonWapImg: string
   refundReasonWapExplain: string
   refundReasonTime: Date
@@ -63,8 +65,176 @@ export const getStoreOrder = async (id: number) => {
   return await request.get({ url: `/order/store-order/get?id=` + id })
 }
 
+export interface IOrder {
+  orderId: string
+  extendOrderId: string
+  uid: number
+  realName: string
+  userPhone: string
+  statusStr: string
+  userAddress: string
+  cartId: string
+  freightPrice: number
+  totalNum: number
+  totalPrice: number
+  totalPostage: number
+  payPrice: number
+  payPostage: number
+  deductionPrice: number
+  couponId: number
+  couponPrice: number
+  paid: number
+  payTime: any // date-time
+  payType: string
+  status: number
+  refundStatus: number
+  refundReasonWapImg: string
+  refundReasonWapExplain: string
+  refundReasonTime: string // date-time
+  refundReasonWap: string
+  refundReason: string
+  refundPrice: number
+  deliverySn: string
+  deliveryName: string
+  deliveryType: string
+  deliveryId: string
+  gainIntegral: number
+  useIntegral: number
+  payIntegral: number
+  backIntegral: number
+  mark: string
+  unique: string
+  remark: string
+  merId: number
+  combinationId: number
+  pinkId: number
+  cost: number
+  seckillId: number
+  bargainId: number
+  verifyCode: string
+  storeId: number
+  shippingType: number
+  isChannel: number
+  isSystemDel: number
+  orderType: string
+  numberId: number
+  shopId: number
+  shopName: string
+  getTime: string // date-time
+  deskId: number
+  deskNumber: string
+  deskPeople: number
+  reachTime: string
+  /**
+   * 预约时间
+   */
+  dueTime: any
+  dueStatus: number
+  createTime: any // date-time
+  id: number
+
+  userRespVO: UserRespVO
+  storeOrderCartInfoDOList: StoreOrderCartInfoDO[]
+  shopDeskDO: ShopDeskDO
+  appDeskOrderVo: AppDeskOrderVo[]
+}
+
+interface UserRespVO {
+  id: number
+  username: string
+  nickname: string
+  remark: string
+  deptId: number
+  deptName: string
+  postIds: number[]
+  email: string
+  mobile: string
+  sex: number
+  avatar: string
+  status: number
+  loginIp: string
+  loginDate: string
+  createTime: string
+}
+
+export interface StoreOrderCartInfoDO {
+  id: number
+  oid: number
+  orderId: string
+  cartId: number
+  productId: number
+  cartInfo: string
+  unique: string
+  isAfterSales: number
+  title: string
+  image: string
+  number: number
+  spec: string
+  price: number
+  addProductMark: number
+  isOrder: number
+  uid: number
+  uidType: string
+  addTime: string
+  unickname: string
+  uavatar: string
+}
+
+interface ShopDeskDO {
+  createTime: string
+  updateTime: string
+  creator: string
+  updater: string
+  deleted: boolean
+  id: number
+  shopId: number
+  shopName: string
+  cateId: number
+  cateName: string
+  title: string
+  image: string
+  number: string
+  miniQrcode: string
+  h5Qrcode: string
+  aliQrcode: string
+  note: string
+  orderCount: number
+  costAmount: number
+  lastOrderNo: string
+  lastOrderTime: string
+  lastOrderStatus: number
+  status: number
+  dueStatus: number
+  dueTime: string
+  reachTime: string
+}
+
+interface AppDeskOrderVo {
+  uid: number
+  addTime: any
+  uavatar: string
+  unickname: string
+  isOrder: number
+  uidType: string
+  addProductMark: number
+  appDeskOrderGoodsVos: AppDeskOrderGoodsVo[]
+}
+
+interface AppDeskOrderGoodsVo {
+  id: number
+  title: string
+  image: string
+  number: number
+  price: number
+  spec: string
+  unickname: string
+  uavatar: string
+  statusStr: string
+}
+
+// 查询订单详情
 export const getStoreOrderInfo = async (id) => {
-  return await request.get({ url: `/order/store-order/getInfo?orderId=` + id })
+  return await request.get<IOrder>({ url: `/order/store-order/getInfo?orderId=` + id })
 }
 
 // 新增订单
@@ -77,20 +247,43 @@ export const updateStoreOrder = async (data: StoreOrderVO) => {
   return await request.put({ url: `/order/store-order/update`, data })
 }
 
-
 // 修改订单
 export const printStoreOrder = async (data: StoreOrderVO) => {
   return await request.put({ url: `/order/store-order/print`, data })
 }
 
-
 // 删除订单
 export const deleteStoreOrder = async (id: number) => {
   return await request.delete({ url: `/order/store-order/delete?id=` + id })
 }
 
+export enum EPAY_TYPE {
+  // 现金支付
+  CASH = 'cash',
+  // Paypay支付
+  PAYPAY = 'paypay',
+  // 信用卡支付
+  CREDIT = 'credit_card',
+  // 西瓜卡支付
+  SUICA = 'suica',
+  // ID支付
+  ID = 'id',
+  // 日本快捷支付
+  QUICKPAY = 'quick_pay',
+  // 乐天支付
+  RAKUTENPAY = 'rekuten_pay '
+}
+export interface IPayStoreOrderQueryParams {
+  id: number
+  payType: EPAY_TYPE
+}
+
+export const payStoreOrderWithPayType = async (data: IPayStoreOrderQueryParams) => {
+  return await request.post({ url: `/order/store-order/pay`, data })
+}
+
 export const payStoreOrder = async (id: number) => {
-  return await request.get({ url: `/order/store-order/pay?id=` + id })
+  return await request.get({ url: `/order/store-order/pay?id=`, id })
 }
 
 export const takeStoreOrder = async (id: number) => {
@@ -98,38 +291,34 @@ export const takeStoreOrder = async (id: number) => {
 }
 
 export const rufundStoreOrder = async (data) => {
-  return await request.post({ url: `/order/store-order/refund`,data })
+  return await request.post({ url: `/order/store-order/refund`, data })
 }
 
-
 export const getStoreOrderRecordList = async (id: number) => {
   return await request.get({ url: `/order/store-order/record-list?id=` + id })
 }
 
-
-
 // 导出订单 Excel
 export const exportStoreOrder = async (params) => {
   return await request.download({ url: `/order/store-order/export-excel`, params })
 }
 
-export const getLogistic = async (param1,param2) => {
-  return await request.get({ url: `/order/express/getLogistic?shipperCode=` + param1 + `&logisticCode=` + param2})
+export const getLogistic = async (param1, param2) => {
+  return await request.get({ url: `/order/express/getLogistic?shipperCode=` + param1 + `&logisticCode=` + param2 })
 }
 
-export const getOrderHtml = async (param1,param2) => {
-  return await request.get({ url: `/order/store-order/printOrder?id=` + param1 + `&electId=` + param2})
+export const getOrderHtml = async (param1, param2) => {
+  return await request.get({ url: `/order/store-order/printOrder?id=` + param1 + `&electId=` + param2 })
 }
 
 export const getShopCount = async () => {
-  return await request.get({ url: `/order/store-order/count`})
+  return await request.get({ url: `/order/store-order/count` })
 }
 
 export const orderNoticeUrl = async () => {
-  return await request.get({ url: `/order/store-order/notice`})
+  return await request.get({ url: `/order/store-order/notice` })
 }
 
 export const orderDueCancel = async (id: number) => {
   return await request.get({ url: `/order/store-order/dueCancel?id=` + id })
 }
-

+ 10 - 0
src/router/modules/remaining.ts

@@ -184,6 +184,16 @@ const remainingRouter: AppRouteRecordRaw[] = [
       noTagsView: true
     }
   },
+  {
+    path: '/register',
+    component: () => import('@/views/Login/Register.vue'),
+    name: 'Register',
+    meta: {
+      hidden: true,
+      title: t('router.register'),
+      noTagsView: true
+    }
+  },
   {
     path: '/sso',
     component: () => import('@/views/Login/Login.vue'),

+ 88 - 0
src/views/Login/Register.vue

@@ -0,0 +1,88 @@
+<template>
+  <div :class="prefixCls" class="h-[100%] relative <xl:bg-v-dark <sm:px-10px <xl:px-10px <md:px-10px">
+    <div class="relative h-full flex mx-auto">
+      <div :class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px <xl:hidden`">
+        <!-- 左上角的 logo + 系统标题 -->
+        <div class="flex items-center relative text-white">
+          <img alt="" class="w-48px h-48px mr-10px" src="@/assets/imgs/logo.png" />
+          <span class="text-20px font-bold">Tabemate Pro オーダーシステム</span>
+        </div>
+        <!-- 左边的背景图 + 欢迎语 -->
+        <div class="flex justify-center items-center h-[calc(100%-60px)]">
+          <TransitionGroup appear enter-active-class="animate__animated animate__bounceInLeft" tag="div">
+            <img key="1" alt="" class="w-500px" src="@/assets/imgs/login_bg.png" />
+            <div key="2" class="text-3xl text-white" style="text-align: center">Tabemate Pro オーダーシステムへようこそ</div>
+            <!-- <div key="3" class="mt-5 font-normal text-white text-14px">
+              {{ t('login.message') }}
+            </div> -->
+          </TransitionGroup>
+        </div>
+      </div>
+      <div class="flex-1 p-30px <sm:p-10px dark:bg-v-dark relative">
+        <!-- 右上角的主题、语言选择 -->
+        <div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
+          <div class="flex items-center @2xl:hidden xl:hidden">
+            <img alt="" class="w-48px h-48px mr-10px @gl:hidden" src="@/assets/imgs/logo.png" />
+            <span class="text-20px font-bold c-black">Tabemate Pro オーダーシステム</span>
+          </div>
+          <div class="flex justify-end items-center space-x-10px">
+            <!-- <ThemeSwitch /> -->
+            <!-- <LocaleDropdown class="<xl:text-white dark:text-white" /> -->
+          </div>
+        </div>
+        <!-- 右边的登录界面 -->
+        <Transition appear enter-active-class="animate__animated animate__bounceInRight">
+          <div class="h-full flex items-center m-auto w-[100%] @2xl:max-w-500px @xl:max-w-500px @md:max-w-500px @lg:max-w-500px">
+            <!-- 账号登录 -->
+            <!-- <LoginForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> -->
+            <!-- 手机登录 -->
+            <!-- <MobileForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
+             二维码登录 -->
+            <!-- <QrCodeForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
+             注册 -->
+            <RegisterForm class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" />
+            <!-- 三方登录 -->
+            <!-- <SSOLoginVue class="p-20px h-auto m-auto <xl:(rounded-3xl light:bg-white)" /> -->
+          </div>
+        </Transition>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" name="Login" setup>
+
+import { useDesign } from '@/hooks/web/useDesign'
+import { useAppStore } from '@/store/modules/app'
+//import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
+//import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
+
+import { RegisterForm } from './components'
+// import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components'
+
+const { t } = useI18n()
+const appStore = useAppStore()
+const { getPrefixCls } = useDesign()
+const prefixCls = getPrefixCls('login')
+appStore.setIsDark(false)
+</script>
+
+<style lang="scss" scoped>
+$prefix-cls: #{$namespace}-login;
+
+.#{$prefix-cls} {
+  &__left {
+    &::before {
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: -1;
+      width: 100%;
+      height: 100%;
+      background-image: url('@/assets/svgs/login-bg.svg');
+      background-position: center;
+      background-repeat: no-repeat;
+      content: '';
+    }
+  }
+}
+</style>

+ 179 - 121
src/views/Login/components/RegisterForm.vue

@@ -1,142 +1,200 @@
 <template>
-  <Form
+  <el-form
     v-show="getShow"
-    :rules="rules"
-    :schema="schema"
-    class="dark:(border-1 border-[var(--el-border-color)] border-solid)"
-    hide-required-asterisk
+    ref="formLogin"
+    :model="registerData.registerForm"
+    :rules="RegisterRules"
+    class="login-form"
     label-position="top"
+    label-width="120px"
     size="large"
-    @register="register"
   >
-    <template #title>
-      <LoginFormTitle style="width: 100%" />
-    </template>
-
-    <template #code="form">
-      <div class="w-[100%] flex">
-        <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" />
-      </div>
-    </template>
-
-    <template #register>
-      <div class="w-[100%]">
-        <XButton
-          :loading="loading"
-          :title="t('login.register')"
-          class="w-[100%]"
-          type="primary"
-          @click="loginRegister()"
-        />
-      </div>
-      <div class="mt-15px w-[100%]">
-        <XButton :title="t('login.hasUser')" class="w-[100%]" @click="handleBackLogin()" />
-      </div>
-    </template>
-  </Form>
+    <el-row style="maring-left: -10px; maring-right: -10px">
+      <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item>
+          <LoginFormTitle style="width: 100%" />
+        </el-form-item>
+      </el-col>
+      <el-col v-if="locale" :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item>
+          <LocaleSelect />
+        </el-form-item>
+      </el-col>
+      <!-- <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item v-if="registerData.tenantEnable === 'true'" prop="tenantName">
+          <el-input
+            v-model="registerData.registerForm.tenantName"
+            :placeholder="t('login.tenantNamePlaceholder')"
+            :prefix-icon="iconHouse"
+            type="primary"
+            link
+          />
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item prop="mobile">
+          <el-input v-model="registerData.registerForm.mobile" :placeholder="t('login.mobileNumber')" :prefix-icon="iconAvatar" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item prop="password">
+          <el-input v-model="registerData.registerForm.password" :placeholder="t('login.password')" :prefix-icon="iconAvatar" />
+        </el-form-item>
+      </el-col>
+      <!-- <el-col :span="24" style="padding-left: 10px; padding-right: 10px; margin-top: -20px; margin-bottom: -20px">
+        <el-form-item>
+          <el-row justify="space-between" style="width: 100%">
+            <el-col :span="6">
+              <el-checkbox v-model="registerData.registerForm">
+                {{ t('login.register') }}
+              </el-checkbox>
+            </el-col>
+          </el-row>
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
+        <el-form-item>
+          <XButton :loading="loginLoading" :title="t('login.login')" class="w-[100%]" type="primary" @click="register()" />
+        </el-form-item>
+      </el-col>
+      <!-- <Verify ref="verify" :captchaType="captchaType" :imgSize="{ width: '400px', height: '200px' }" mode="pop" @success="handleLogin" /> -->
+    </el-row>
+  </el-form>
 </template>
-<script lang="ts" setup>
-import type { FormRules } from 'element-plus'
-
-import { useForm } from '@/hooks/web/useForm'
-import { useValidator } from '@/hooks/web/useValidator'
+<script lang="ts" name="LoginForm" setup>
+import { ElLoading } from 'element-plus'
 import LoginFormTitle from './LoginFormTitle.vue'
-import { LoginStateEnum, useLoginState } from './useLogin'
-import { FormSchema } from '@/types/form'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
 
-defineOptions({ name: 'RegisterForm' })
+import { useIcon } from '@/hooks/web/useIcon'
 
+import * as authUtil from '@/utils/auth'
+import { usePermissionStore } from '@/store/modules/permission'
+import * as LoginApi from '@/api/login'
+import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
+import { LocaleSelect } from '@/layout/components/LocaleDropdown'
+import { useAppStore } from '@/store/modules/app'
 const { t } = useI18n()
-const { required } = useValidator()
-const { register, elFormRef } = useForm()
-const { handleBackLogin, getLoginState } = useLoginState()
-const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)
+//const message = useMessage()
+const iconAvatar = useIcon({ icon: 'ep:avatar' })
+const iconLock = useIcon({ icon: 'ep:lock' })
+const formLogin = ref()
+const { validForm } = useFormValid(formLogin)
+const { getLoginState, setLoginState } = useLoginState()
+const { currentRoute, push } = useRouter()
+const permissionStore = usePermissionStore()
+const redirect = ref<string>('')
+const loginLoading = ref(false)
+const verify = ref()
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+const appStore = useAppStore()
+const locale = computed(() => appStore.getLocale)
+const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
 
-const schema = reactive<FormSchema[]>([
-  {
-    field: 'title',
-    colProps: {
-      span: 24
-    }
-  },
-  {
-    field: 'username',
-    label: t('login.username'),
-    value: '',
-    component: 'Input',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      placeholder: t('login.usernamePlaceholder')
+const RegisterRules = {
+  mobile: [required],
+  password: [required]
+}
+const registerData = reactive({
+  isShowPassword: false,
+  captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
+  tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
+  registerForm: {
+    mobile: '',
+    password: ''
+  }
+})
+
+// 获取验证码
+const getCode = async () => {
+  // 情况一,未开启:则直接登录
+  console.log('oginData.captchaEnable:', registerData.captchaEnable)
+  if (registerData.captchaEnable === 'false') {
+    // await register({
+
+    // })
+  } else {
+    // 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录
+    // 弹出验证码
+    // verify.value.show()
+  }
+}
+//获取租户ID
+const getTenantId = async () => {
+  // if (registerData.tenantEnable === 'true') {
+  //   const res = await LoginApi.getTenantIdByName(registerData.registerForm.tenantName)
+  //   authUtil.setTenantId(res)
+  // }
+}
+// 记住我
+const getCookie = () => {
+  // const loginForm = authUtil.getLoginForm()
+  // if (loginForm) {
+  //   registerData.registerForm = {
+  //     ...registerData.registerForm,
+  //     password: loginForm.password ? loginForm.password : registerData.registerForm.password,
+  //   }
+  // }
+}
+// 注册
+const register = async () => {
+  loginLoading.value = true
+  try {
+    await getTenantId()
+    const data = await validForm()
+    if (!data) {
+      return
     }
-  },
-  {
-    field: 'password',
-    label: t('login.password'),
-    value: '',
-    component: 'InputPassword',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      style: {
-        width: '100%'
-      },
-      strength: true,
-      placeholder: t('login.passwordPlaceholder')
+    registerData.registerForm.captchaVerification = params.captchaVerification
+    const res = await LoginApi.login(registerData.registerForm)
+    if (!res) {
+      return
     }
-  },
-  {
-    field: 'check_password',
-    label: t('login.checkPassword'),
-    value: '',
-    component: 'InputPassword',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      style: {
-        width: '100%'
-      },
-      strength: true,
-      placeholder: t('login.passwordPlaceholder')
+    ElLoading.service({
+      lock: true,
+      text: t('login.loadingSystem'),
+      background: 'rgba(0, 0, 0, 0.7)'
+    })
+    if (registerData.registerForm.rememberMe) {
+      authUtil.setLoginForm(registerData.registerForm)
+    } else {
+      authUtil.removeLoginForm()
     }
-  },
-  {
-    field: 'code',
-    label: t('login.code'),
-    colProps: {
-      span: 24
+    authUtil.setToken(res)
+    if (!redirect.value) {
+      redirect.value = '/'
     }
-  },
-  {
-    field: 'register',
-    colProps: {
-      span: 24
+    // 判断是否为SSO登录
+    if (redirect.value.indexOf('sso') !== -1) {
+      window.location.href = window.location.href.replace('/login?redirect=', '')
+    } else {
+      push({ path: redirect.value || permissionStore.addRouters[0].path })
     }
+  } catch {
+    loginLoading.value = false
+  } finally {
+    setTimeout(() => {
+      const loadingInstance = ElLoading.service()
+      loadingInstance.close()
+    }, 400)
   }
-])
-
-const rules: FormRules = {
-  username: [required()],
-  password: [required()],
-  check_password: [required()],
-  code: [required()]
 }
 
-const loading = ref(false)
-
-const loginRegister = async () => {
-  const formRef = unref(elFormRef)
-  formRef?.validate(async (valid) => {
-    if (valid) {
-      try {
-        loading.value = true
-      } finally {
-        loading.value = false
-      }
+watch(
+  () => currentRoute.value,
+  (route: RouteLocationNormalizedLoaded) => {
+    if (route.name === 'register') {
+      setLoginState(LoginStateEnum.REGISTER)
+      // init()
     }
-  })
-}
+  },
+  { immediate: true }
+)
+onMounted(() => {
+  getCookie()
+})
 </script>
+
+<style lang="scss" scoped>
+
+</style>

+ 1 - 1
src/views/Login/components/SSOLogin.vue

@@ -192,7 +192,7 @@ watch(
   (route: RouteLocationNormalizedLoaded) => {
     if (route.name === 'SSOLogin') {
       setLoginState(LoginStateEnum.SSO)
-      init()
+      init() 
     }
   },
   { immediate: true }

+ 5 - 5
src/views/mall/order/storeOrder/OrderDetail.vue

@@ -32,20 +32,20 @@
                       item.uidType == 'user' ? t('mall.userOrdering') : t('mall.staffOrderingOnBehalf')
                     }}</span>
                     <span style="color: #5ac725">({{ item.isOrder == 0 ? t('mall.mealNotServed') : t('mall.mealServed') }})</span>
-                  <el-divider />
-                  <div class="flex align-center" v-for="(good,index2) in item.appDeskOrderGoodsVos" :key="index2">
+                  <!-- <el-divider /> -->
+                  <!-- <div class="flex align-center" v-for="(good,index2) in item.appDeskOrderGoodsVos" :key="index2">
                     <div><el-image :src="convertImageUrl(good.image)" style="width: 70px;height: 70px;" /></div>
                     <div class="flex  flex-1 flex-column ml-2 font-size-sm">
                         <div class="flex justify-between"><span class="font-weight-bolder">{{good.title}}</span><span style="color: #f56c6c;">{{good.spec}}</span></div>
                         <div class="flex justify-between mt-1"><span>¥{{good.price}}</span><span>x{{good.number}}</span></div>
                     </div>
-                  </div>
-                  <div style="">
+                  </div> -->
+                  <!-- <div style="">
                     <span style="color: #9acafc; font-weight: bold">{{
                       item.uidType == 'user' ? t('mall.userOrdering') : t('mall.staffOrderingOnBehalf')
                     }}</span>
                     <span style="color: #5ac725">({{ item.isOrder == 0 ? t('mall.mealNotServed') : t('mall.mealServed') }})</span>
-                  </div>
+                  </div> -->
                 </div>
               </div>
             </div>

+ 157 - 112
src/views/mall/order/storeOrder/OrderDetail2.vue

@@ -1,6 +1,6 @@
 <template>
- <el-drawer v-model="drawer" :title="dialogTitle" size="35%">
-    <div>
+  <el-drawer v-model="drawer" :title="dialogTitle" size="35%">
+    <div v-if="DetailData">
       <el-descriptions :title="t('mall.receivingInfoOne')" :column="2" v-if="DetailData.orderType == 'takeout'">
         <el-descriptions-item :label="t('mall.userNickname')">{{ nickname }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.consignee')">{{ DetailData.realName }}</el-descriptions-item>
@@ -8,79 +8,107 @@
         <el-descriptions-item :label="t('mall.receivingAddress')">{{ DetailData.userAddress }}</el-descriptions-item>
       </el-descriptions>
       <el-descriptions title="" :column="1" v-if="DetailData.orderType != 'due'">
-          <el-descriptions-item>
-            <template #label>
-              <div class="mylabel">
-                {{ t('mall.dishDetails') }}
-              </div>
-            </template>
-            <div>
-                <div style="background: linear-gradient(to bottom, #e9f1ee, #fcfcf4);padding: 20px 30px;margin: 10px 0;border-radius: 20px;" v-for="(item, index) in DetailData.appDeskOrderVo" :key="index">
-                  <div class="flex align-center">
-                    <div><el-avatar :size="50" :src="item.uavatar" /></div>
-                    <div class="flex flex-1 justify-between font-size-sm text-color-assist">
-                      <div class="flex flex-column ml-2">
-                        <span>{{item.unickname}}</span>
-                        <span>{{formatDate(item.addTime) }}</span>
-                      </div>
-                      <div style="">
-                        <span style="color: #9acafc;font-weight: bold;">{{item.uidType == 'user' ?  t('mall.userOrdering') :  t('mall.staffOrderingOnBehalf')}}</span>
-                        <span style="color: #5ac725;">({{item.isOrder == 0 ?  t('mall.mealNotServed') :  t('mall.mealServed')}})</span>
-                      </div>
-                    </div>
+        <el-descriptions-item>
+          <template #label>
+            <div class="mylabel">
+              {{ t('mall.dishDetails') }}
+            </div>
+          </template>
+          <div>
+            <div
+              style="background: linear-gradient(to bottom, #e9f1ee, #fcfcf4); padding: 20px 30px; margin: 10px 0; border-radius: 20px"
+              v-for="(item, index) in DetailData.appDeskOrderVo"
+              :key="index"
+            >
+              <div class="flex align-center">
+                <div><el-avatar :size="50" :src="item.uavatar" /></div>
+                <div class="flex flex-1 justify-between font-size-sm text-color-assist">
+                  <div class="flex flex-column ml-2">
+                    <span>{{ item.unickname }}</span>
+                    <span>{{ formatDate(item.addTime) }}</span>
                   </div>
-                  <el-divider />
-                  <div class="flex align-center" v-for="(good,index2) in item.appDeskOrderGoodsVos" :key="index2">
-                    <div><el-image :src="convertImageUrl(good.image)" style="width: 70px;height: 70px;" /></div>
-                    <div class="flex  flex-1 flex-column ml-2 font-size-sm">
-                        <div class="flex justify-between"><span class="font-weight-bolder">{{good.title}}</span><span style="color: #f56c6c;">{{good.spec}}</span></div>
-                        <div class="flex justify-between mt-1"><span>¥{{good.price}}</span><span>x{{good.number}}</span></div>
-                    </div>
+                  <div style="">
+                    <span style="color: #9acafc; font-weight: bold">{{
+                      item.uidType == 'user' ? t('mall.userOrdering') : t('mall.staffOrderingOnBehalf')
+                    }}</span>
+                    <span style="color: #5ac725">({{ item.isOrder == 0 ? t('mall.mealNotServed') : t('mall.mealServed') }})</span>
                   </div>
                 </div>
+              </div>
+              <el-divider />
+              <div class="flex align-center" v-for="(good, index2) in item.appDeskOrderGoodsVos" :key="index2">
+                <div><el-image :src="convertImageUrl(good.image)" style="width: 70px; height: 70px" /></div>
+                <div class="flex flex-1 flex-column ml-2 font-size-sm">
+                  <div class="flex justify-between"
+                    ><span class="font-weight-bolder">{{ good.title }}</span
+                    ><span style="color: #f56c6c">{{ good.spec }}</span></div
+                  >
+                  <div class="flex justify-between mt-1"
+                    ><span>¥{{ good.price }}</span
+                    ><span>x{{ good.number }}</span></div
+                  >
+                </div>
+              </div>
             </div>
-          </el-descriptions-item>
+          </div>
+        </el-descriptions-item>
       </el-descriptions>
       <el-descriptions :title="t('mall.productDetails')" :column="1" v-else>
-          <el-descriptions-item :label="t('mall.reserveTable')">
-              <table width="100%">
-                <tr style="font-weight:bold;height:50px">
-                  <td>{{t('mall.picture')}}</td>
-                  <td>{{t('mall.name')}}</td>
-                  <td>{{t('mall.price')}}</td>
-                  <td>{{t('mall.quantity')}}</td>
-                </tr>
-                <tr>
-                    <td><el-image style="width: 40px; height: 40px" :src="DetailData.shopDeskDO.image" :fit="fit" /></td>
-                    <td>{{ DetailData.shopDeskDO.title}}</td>
-                    <td>¥0.00</td>
-                    <td>x 1</td>
-                </tr>
-              </table>
-          </el-descriptions-item>
+        <el-descriptions-item :label="t('mall.reserveTable')">
+          <table width="100%">
+            <tr style="font-weight: bold; height: 50px">
+              <td>{{ t('mall.picture') }}</td>
+              <td>{{ t('mall.name') }}</td>
+              <td>{{ t('mall.price') }}</td>
+              <td>{{ t('mall.quantity') }}</td>
+            </tr>
+            <tr>
+              <td><el-image style="width: 40px; height: 40px" :src="DetailData.shopDeskDO.image" fit="fill" /></td>
+              <td>{{ DetailData.shopDeskDO.title }}</td>
+              <td>¥0.00</td>
+              <td>x 1</td>
+            </tr>
+          </table>
+        </el-descriptions-item>
       </el-descriptions>
       <el-descriptions :title="t('mall.orderInfo')" :column="2">
         <template #title>
           {{ t('mall.orderInfo') }}
-          <el-tag  type="danger" v-if="DetailData.orderType=='desk'">{{ t('mall.dineIn') }}</el-tag>
-          <el-tag  type="danger" v-if="DetailData.orderType=='takeout'">{{t('mall.takeOut')}}</el-tag>
-          <el-tag  type="danger" v-if="DetailData.orderType=='takein'">{{t('mall.pickup')}}</el-tag>
-          <el-tag  type="danger" v-if="DetailData.orderType=='due'">{{ t('mall.reservation') }}</el-tag>
+          <el-tag type="danger" v-if="DetailData.orderType == 'desk'">{{ t('mall.dineIn') }}</el-tag>
+          <el-tag type="danger" v-if="DetailData.orderType == 'takeout'">{{ t('mall.takeOut') }}</el-tag>
+          <el-tag type="danger" v-if="DetailData.orderType == 'takein'">{{ t('mall.pickup') }}</el-tag>
+          <el-tag type="danger" v-if="DetailData.orderType == 'due'">{{ t('mall.reservation') }}</el-tag>
         </template>
         <el-descriptions-item :label="t('mall.store')">{{ DetailData.shopName }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.pickupNumber')" v-if="DetailData.orderType != 'due'">{{ DetailData.numberId }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.tableNumber')">{{ DetailData.deskNumber ? DetailData.deskNumber : t('public.none') }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.numberOfDiners')" v-if="DetailData.orderType != 'due'">{{ DetailData.deskPeople ? DetailData.deskPeople : t('public.none') }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.pickupNumber')" v-if="DetailData.orderType != 'due'">{{
+          DetailData.numberId
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.tableNumber')">{{
+          DetailData.deskNumber ? DetailData.deskNumber : t('public.none')
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.numberOfDiners')" v-if="DetailData.orderType != 'due'">{{
+          DetailData.deskPeople ? DetailData.deskPeople : t('public.none')
+        }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.orderNo')">{{ DetailData.orderId }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.reservationTime')" v-if="DetailData.orderType == 'due'">{{ formatDate(DetailData.dueTime) }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.arrivalTime')" v-if="DetailData.orderType == 'due'">{{ DetailData.reachTime }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.reservationPerson')" v-if="DetailData.orderType == 'due'">{{ DetailData.realName }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.reservationPhone')" v-if="DetailData.orderType == 'due'">{{ DetailData.userPhone }}</el-descriptions-item>
-        <el-descriptions-item :label="t('mall.orderStatus')" v-if="DetailData.orderType != 'due'">{{ DetailData.statusStr }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.reservationTime')" v-if="DetailData.orderType == 'due'">{{
+          formatDate(DetailData.dueTime)
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.arrivalTime')" v-if="DetailData.orderType == 'due'">{{
+          DetailData.reachTime
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.reservationPerson')" v-if="DetailData.orderType == 'due'">{{
+          DetailData.realName
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.reservationPhone')" v-if="DetailData.orderType == 'due'">{{
+          DetailData.userPhone
+        }}</el-descriptions-item>
+        <el-descriptions-item :label="t('mall.orderStatus')" v-if="DetailData.orderType != 'due'">{{
+          DetailData.statusStr
+        }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.reservationStatus')" v-if="DetailData.orderType == 'due'">
-          <span v-if="DetailData.dueStatus == 1">{{t('mall.reserving')}}</span>
-          <span v-else-if="DetailData.dueStatus == 2">{{t('mall.cancelled')}}</span>
-          <span v-else>{{t('mall.completed')}}</span>
+          <span v-if="DetailData.dueStatus == 1">{{ t('mall.reserving') }}</span>
+          <span v-else-if="DetailData.dueStatus == 2">{{ t('mall.cancelled') }}</span>
+          <span v-else>{{ t('mall.completed') }}</span>
         </el-descriptions-item>
         <el-descriptions-item :label="t('mall.totalProductQuantity')">{{ DetailData.totalNum }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.totalProductPrice')">{{ DetailData.totalPrice }}</el-descriptions-item>
@@ -89,36 +117,31 @@
         <el-descriptions-item :label="t('mall.pointsDeduction')">{{ DetailData.useIntegral }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.actualPayment')">{{ DetailData.payPrice }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.bonusPoints')">{{ DetailData.gainIntegral }}</el-descriptions-item>
-        <el-descriptions-item :label="t('public.createTime')">{{ formatDate(DetailData.createTime)}}</el-descriptions-item>
+        <el-descriptions-item :label="t('public.createTime')">{{ formatDate(DetailData.createTime) }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.paymentTime')">{{ formatDate(DetailData.payTime) }}</el-descriptions-item>
         <el-descriptions-item :label="t('mall.paymentMethod')">{{ DetailData.payType }}</el-descriptions-item>
       </el-descriptions>
-      <div style="margin-top:50px;text-align:center">
-        <el-button type="primary" @click="openHelp()">{{t('mall.assistWithOrdering')}}</el-button>
-        <el-button type="success" @click="handlePay(DetailData.id)">{{t('mall.confirmCollection')}}</el-button>
-        <el-button type="danger" @click="handlePrint(DetailData.orderId)">{{t('mall.issueOrderAndPrintReceipt')}}</el-button>
+      <div style="margin-top: 50px; text-align: center">
+        <el-button type="primary" @click="openHelp()">{{ t('mall.assistWithOrdering') }}</el-button>
+        <el-button type="success" @click="handlePay(DetailData.id)">{{ t('mall.confirmCollection') }}</el-button>
+        <el-button type="danger" @click="handlePrint(DetailData.orderId)">{{ t('mall.issueOrderAndPrintReceipt') }}</el-button>
       </div>
     </div>
   </el-drawer>
   <helpOrder ref="helpOrderRef" />
-  
+
   <!-- 支付方式选择对话框 -->
-  <el-dialog
-    v-model="showPaymentDialog"
-    :title="t('mall.confirmOfflineCollection')"
-    width="400px"
-    class="payment-dialog"
-  >
+  <el-dialog v-model="showPaymentDialog" :title="t('mall.confirmOfflineCollection')" width="400px" class="payment-dialog">
     <el-radio-group v-model="selectedPayment" class="payment-methods">
-      <el-radio label="cash" size="large" border>{{ t('mall.cashPayment') }}</el-radio>
-      <el-radio label="paypay" size="large" border>PayPay</el-radio>
-      <el-radio label="credit_card" size="large" border>{{ t('mall.creditCard') }}</el-radio>
-      <el-radio label="suica" size="large" border>Suica</el-radio>
-      <el-radio label="id" size="large" border>ID</el-radio>
-      <el-radio label="quick_pay" size="large" border>QuickPay</el-radio>
-      <el-radio label="rakuten_pay" size="large" border>{{ t('mall.rakutenPay') }}</el-radio>
+      <el-radio :value="EPAY_TYPE.CASH" label="cash" size="large" border>{{ t('mall.cashPayment') }}</el-radio>
+      <el-radio :value="EPAY_TYPE.PAYPAY" label="paypay" size="large" border>PayPay</el-radio>
+      <el-radio :value="EPAY_TYPE.CREDIT" label="credit_card" size="large" border>{{ t('mall.creditCard') }}</el-radio>
+      <el-radio :value="EPAY_TYPE.SUICA" label="suica" size="large" border>Suica</el-radio>
+      <el-radio :value="EPAY_TYPE.ID" label="id" size="large" border>ID</el-radio>
+      <el-radio :value="EPAY_TYPE.QUICKPAY" label="quick_pay" size="large" border>QuickPay</el-radio>
+      <el-radio :value="EPAY_TYPE.RAKUTENPAY" label="rakuten_pay" size="large" border>{{ t('mall.rakutenPay') }}</el-radio>
     </el-radio-group>
-    
+
     <template #footer>
       <span class="dialog-footer">
         <el-button @click="showPaymentDialog = false">{{ t('common.cancel') }}</el-button>
@@ -134,10 +157,11 @@ import * as StoreOrderApi from '@/api/mall/order/storeOrder'
 import { formatDate } from '@/utils/formatTime'
 import helpOrder from '@/views/mall/cashier/help.vue'
 import * as CashierApi from '@/api/mall/cashier'
-import {  ElMessage } from 'element-plus'
-import { ref  } from 'vue'
+import { ElMessage } from 'element-plus'
+import { ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
-import type { PaymentData } from '@/api/mall/order/storeOrder'
+import { EPAY_TYPE, IOrder, StoreOrderCartInfoDO } from '@/api/mall/order/storeOrder'
+import { convertImageUrl } from '@/utils/image-helper'
 import { ElRadioGroup, ElRadio } from 'element-plus'
 //const message = useMessage() // 消息弹窗
 
@@ -145,41 +169,40 @@ const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 const dialogTitle = ref('') // 弹窗的标题
 const drawer = ref(false)
-const DetailData = ref({})
+const DetailData = ref<IOrder>()
 const nickname = ref('')
 const logisticResult = ref({})
-const product = ref([])
+const product = ref<StoreOrderCartInfoDO[]>([])
 const addProductMark = ref(0)
 const deskInfo = ref({})
-const selectedPayment = ref('cash')
+const selectedPayment = ref<EPAY_TYPE>(EPAY_TYPE.CASH)
 const showPaymentDialog = ref(false)
 const currentOrderId = ref<number | null>(null)
 /** 打开弹窗 */
 const open = async (desk) => {
   drawer.value = true
   deskInfo.value = desk
-  dialogTitle.value = "桌台:" + desk.number
+  dialogTitle.value = '桌台:' + desk.number
   DetailData.value = await StoreOrderApi.getStoreOrderInfo(desk.lastOrderNo)
   nickname.value = DetailData.value.userRespVO ? DetailData.value.userRespVO.nickname : '--'
   product.value = DetailData.value.storeOrderCartInfoDOList
   //获取加餐数量
-  if(DetailData.value.storeOrderCartInfoDOList && DetailData.value.storeOrderCartInfoDOList.length > 0){
+  if (DetailData.value.storeOrderCartInfoDOList && DetailData.value.storeOrderCartInfoDOList.length > 0) {
     addProductMark.value = DetailData.value.storeOrderCartInfoDOList[DetailData.value.storeOrderCartInfoDOList.length - 1].addProductMark
   }
 
-
-  console.log('addProductMark.value:',addProductMark.value )
+  console.log('addProductMark.value:', addProductMark.value)
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
 const helpOrderRef = ref()
 const openHelp = () => {
   drawer.value = false
-  helpOrderRef.value.open(deskInfo.value,DetailData.value)
+  helpOrderRef.value.open(deskInfo.value, DetailData.value)
 }
 
 const handlePay = async (id: number) => {
-  if(!id) {
+  if (!id) {
     message.error(t('mall.pleasePlaceAnOrderFirst'))
     return
   }
@@ -192,9 +215,17 @@ const confirmPayment = async () => {
     ElMessage.error(t('mall.pleaseSelectPaymentMethod'))
     return
   }
-  
+  // PAYPAY("paypay","Paypay支付"),
+  // CREDIT("credit_card", "信用卡支付"),
+  // SUICA("suica","西瓜卡支付"),
+  // ID("id","ID支付"),
+  // QUICKPAY("quick_pay","日本快捷支付"),
+  // RAKUTENPAY("rekuten_pay", "乐天支付");
   try {
-    await StoreOrderApi.payStoreOrder(currentOrderId.value!)
+    await StoreOrderApi.payStoreOrderWithPayType({
+      id: currentOrderId.value!,
+      payType: selectedPayment.value
+    })
     message.success(t('common.updateSuccess'))
     showPaymentDialog.value = false
     drawer.value = false
@@ -204,7 +235,7 @@ const confirmPayment = async () => {
 }
 
 const handlePrint = async (id) => {
-  if(!id) {
+  if (!id) {
     message.error(t('mall.pleasePlaceAnOrderFirst'))
     return
   }
@@ -212,28 +243,42 @@ const handlePrint = async (id) => {
     //await message.confirm('确定下线收款')
     //await StoreOrderApi.payStoreOrder(id)
     //message.success(t('common.updateSuccess'))
-    await CashierApi.printOrder({orderId:id})
+    await CashierApi.printOrder({ orderId: id })
     message.success(t('mall.orderIssued'))
-   drawer.value = false
-
+    drawer.value = false
   } catch {}
 }
-
 </script>
 <style scoped>
-.flex{
-	/* #ifndef APP-PLUS-NVUE */
-	display:flex;
-	/* #endif */
-	flex-direction:row;
+.flex {
+  /* #ifndef APP-PLUS-NVUE */
+  display: flex;
+  /* #endif */
+  flex-direction: row;
+}
+.justify-between {
+  justify-content: space-between;
+}
+.justify-center {
+  justify-content: center;
+}
+.align-center {
+  align-items: center;
+}
+.flex-1 {
+  flex: 1;
+}
+.flex-column {
+  flex-direction: column !important;
+}
+.ml-2 {
+  margin-left: 20px;
+}
+.mylabel {
+  font-weight: bolder;
+  text-align: center;
+  font-size: 18px;
 }
-.justify-between{justify-content:space-between;}
-.justify-center{justify-content:center;}
-.align-center{ align-items: center; }
-.flex-1{ flex: 1; }
-.flex-column{ flex-direction:column!important; }
-.ml-2 { margin-left: 20px; }
-.mylabel {font-weight:bolder;text-align:center;font-size:18px}
 
 /* 支付方式选择对话框样式 */
 :deep(.payment-dialog) {