Explorar el Código

feat(login): 添加记住我功能并加密存储用户名密码

- 新增 `Crypto` 工具类对本地存储的密码进行加解密处理
- 登录表单支持“记住我”选项,自动填充已保存的账号信息
- 在 `storage.d.ts` 中新增 `userName` 和 `password` 类型定义

refactor(router): 移除订单拆分相关路由及组件文件

- 删除 `/config/order-splitting` 路由配置及其对应的页面文件
- 清理优雅路由相关的导入、路径映射和类型声明
- 更新了菜单标题与字段显示逻辑,优化运费配置表单结构

fix(table): 修正售后订单申请人信息展示及商品积分计算方式

- 售后订单弹窗中增加申请人信息空值判断,避免显示 undefined
- 普通订单详情里积分字段改为负数形式,并以元为单位保留两位小数
- 商品列表页调整列宽并修复规格信息取值错误的问题
zhangtao hace 1 día
padre
commit
ac7d6a53fe

+ 0 - 1
src/locales/langs/en-us.ts

@@ -299,7 +299,6 @@ const local: App.I18n.Schema = {
     operation_search: '',
     config: '',
     'config_fright-config': '',
-    'config_order-splitting': '',
     delivery: '',
     'delivery_normal-order': '',
     'operation_delivery-admin': '',

+ 0 - 1
src/locales/langs/zh-cn.ts

@@ -296,7 +296,6 @@ const local: App.I18n.Schema = {
     operation_search: '',
     config: '',
     'config_fright-config': '',
-    'config_order-splitting': '',
     delivery: '',
     'delivery_normal-order': '',
     'operation_delivery-admin': '',

+ 0 - 1
src/router/elegant/imports.ts

@@ -22,7 +22,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
   login: () => import("@/views/_builtin/login/index.vue"),
   about: () => import("@/views/about/index.vue"),
   "config_fright-config": () => import("@/views/config/fright-config/index.vue"),
-  "config_order-splitting": () => import("@/views/config/order-splitting/index.vue"),
   "delivery_after-sales-order": () => import("@/views/delivery/after-sales-order/index.vue"),
   "delivery_normal-order": () => import("@/views/delivery/normal-order/index.vue"),
   "goods_desk-category": () => import("@/views/goods/desk-category/index.vue"),

+ 0 - 9
src/router/elegant/routes.ts

@@ -67,15 +67,6 @@ export const generatedRoutes: GeneratedRoute[] = [
           title: 'config_fright-config',
           i18nKey: 'route.config_fright-config'
         }
-      },
-      {
-        name: 'config_order-splitting',
-        path: '/config/order-splitting',
-        component: 'view.config_order-splitting',
-        meta: {
-          title: 'config_order-splitting',
-          i18nKey: 'route.config_order-splitting'
-        }
       }
     ]
   },

+ 0 - 1
src/router/elegant/transform.ts

@@ -184,7 +184,6 @@ const routeMap: RouteMap = {
   "about": "/about",
   "config": "/config",
   "config_fright-config": "/config/fright-config",
-  "config_order-splitting": "/config/order-splitting",
   "delivery": "/delivery",
   "delivery_after-sales-order": "/delivery/after-sales-order",
   "delivery_normal-order": "/delivery/normal-order",

+ 0 - 2
src/typings/elegant-router.d.ts

@@ -38,7 +38,6 @@ declare module "@elegant-router/types" {
     "about": "/about";
     "config": "/config";
     "config_fright-config": "/config/fright-config";
-    "config_order-splitting": "/config/order-splitting";
     "delivery": "/delivery";
     "delivery_after-sales-order": "/delivery/after-sales-order";
     "delivery_normal-order": "/delivery/normal-order";
@@ -191,7 +190,6 @@ declare module "@elegant-router/types" {
     | "login"
     | "about"
     | "config_fright-config"
-    | "config_order-splitting"
     | "delivery_after-sales-order"
     | "delivery_normal-order"
     | "goods_desk-category"

+ 9 - 0
src/typings/storage.d.ts

@@ -39,5 +39,14 @@ declare namespace StorageType {
     };
     /** The last login user id */
     lastLoginUserId: string;
+
+    /**
+     * 用户名
+     */
+    userName: string;
+    /**
+     * 密码
+     */
+    password: string;
   }
 }

+ 24 - 5
src/views/_builtin/login/modules/pwd-login.vue

@@ -1,16 +1,19 @@
 <script setup lang="ts">
-import { computed, reactive, ref, watch } from 'vue';
+import { computed, onMounted, reactive, ref, watch } from 'vue';
+import { Crypto } from '@sa/utils';
 import { useAuthStore } from '@/store/modules/auth';
 import { useFormRules, useNaiveForm } from '@/hooks/common/form';
 import { getUUID } from '@/utils/zt';
+import { localStg } from '@/utils/storage';
 import { $t } from '@/locales';
-
 defineOptions({
   name: 'PwdLogin'
 });
+const pd = new Crypto<{ data: string }>('zhongshuweilai');
 
 const authStore = useAuthStore();
 const { formRef, validate } = useNaiveForm();
+const isRememberMe = ref(false);
 const imgPath = ref('');
 interface FormModel {
   userName: string;
@@ -19,11 +22,22 @@ interface FormModel {
 }
 
 const model: FormModel = reactive({
-  userName: 'admin',
-  password: 'root2025',
+  userName: '',
+  password: '',
   imageCode: ''
 });
 
+onMounted(() => {
+  const userName = localStg.get('userName');
+  const password = localStg.get('password');
+  const obj = pd.decrypt(String(password));
+  if (userName && password && obj) {
+    model.userName = userName;
+    model.password = obj.data;
+    isRememberMe.value = true;
+  }
+});
+
 const rules = computed<Record<keyof FormModel, App.Global.FormRule[]>>(() => {
   // inside computed to make locale reactive, if not apply i18n, you can define it without computed
   const { formRules } = useFormRules();
@@ -37,6 +51,11 @@ const rules = computed<Record<keyof FormModel, App.Global.FormRule[]>>(() => {
 const sessionUUID = ref('');
 async function handleSubmit() {
   await validate();
+  if (isRememberMe.value) {
+    const pwd = pd.encrypt({ data: model.password });
+    localStg.set('userName', model.userName);
+    localStg.set('password', pwd);
+  }
   await authStore.login({ ...model, sessionUUID: sessionUUID.value });
 }
 async function getDataCode() {
@@ -77,7 +96,7 @@ watch(
     </NFormItem>
     <NSpace vertical :size="24">
       <div class="flex-y-center justify-between">
-        <NCheckbox>{{ $t('page.login.pwdLogin.rememberMe') }}</NCheckbox>
+        <NCheckbox v-model:checked="isRememberMe">{{ $t('page.login.pwdLogin.rememberMe') }}</NCheckbox>
       </div>
       <NButton type="primary" size="large" round block :loading="authStore.loginLoading" @click="handleSubmit">
         {{ $t('common.confirm') }}

+ 34 - 6
src/views/config/fright-config/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="tsx">
 import { ref } from 'vue';
-import { NDynamicInput, NInputNumber } from 'naive-ui';
+import { NDynamicInput, NInput, NInputNumber } from 'naive-ui';
 import { fetchGetAllChannelList } from '@/service/api/goods/store-goods';
 import { useTabStore } from '@/store/modules/tab';
 import { useForm } from '@/components/zt/Form/hooks/useForm';
@@ -13,6 +13,24 @@ interface Options {
 const ChannelOptions = ref<Api.goods.Channel[]>([]);
 const [registerForm, { getFieldsValue, validate }] = useForm({
   schemas: [
+    {
+      field: '1',
+      component: 'NInput',
+      label: '配送距离',
+      required: true,
+      render({ model, field }) {
+        return (
+          <div class={'w200px xl:w700px'}>
+            <NInput
+              placeholder={'请输入配送距离'}
+              value={model[field]}
+              onUpdate:value={val => (model[field] = val)}
+              v-slots={{ prefix: () => '大于', suffix: () => 'km' }}
+            ></NInput>
+          </div>
+        );
+      }
+    },
     {
       field: 'name',
       component: 'NDynamicInput',
@@ -22,7 +40,8 @@ const [registerForm, { getFieldsValue, validate }] = useForm({
           <div class={'flex flex-wrap items-center'}>
             <div class={'h38px flex items-center'}>
               <div class={'w-200px text-center'}> 企业 </div>
-              <div class={'ml-3 w-200px text-center'}> 费用(元/每20kg) </div>
+              <div class={'ml-3 w-200px text-center'}> 费用(元) </div>
+              <div class={'ml-3 w-200px text-center'}> 重量(kg) </div>
             </div>
             <NDynamicInput
               value={model[field]}
@@ -40,12 +59,12 @@ const [registerForm, { getFieldsValue, validate }] = useForm({
   ],
   labelWidth: 120,
   layout: 'horizontal',
+  collapsedRows: 1,
+  showActionButtonGroup: false,
   gridProps: {
-    cols: '1 xl:4 s:1 l:3',
+    cols: '1',
     itemResponsive: true
-  },
-  collapsedRows: 1,
-  showActionButtonGroup: false
+  }
 });
 function handleCreatInput(model: any, field: any, row: Options) {
   return (
@@ -71,6 +90,15 @@ function handleCreatInput(model: any, field: any, row: Options) {
           }}
         ></NInputNumber>
       </div>
+      <div class={'ml-3 w-200px'}>
+        <NInputNumber
+          value={model[field][row.index].Cost}
+          min={1}
+          onUpdate:value={value => {
+            model[field][row.index].Cost = value;
+          }}
+        ></NInputNumber>
+      </div>
     </div>
   );
 }

+ 0 - 67
src/views/config/order-splitting/index.vue

@@ -1,67 +0,0 @@
-<script setup lang="tsx">
-import { NInput } from 'naive-ui';
-import { useTabStore } from '@/store/modules/tab';
-import { useForm } from '@/components/zt/Form/hooks/useForm';
-const tabStore = useTabStore();
-
-const [registerForm, { getFieldsValue, validate }] = useForm({
-  schemas: [
-    {
-      field: 'name',
-      component: 'NInput',
-      label: '配送距离',
-      required: true,
-      render({ model, field }) {
-        return (
-          <NInput
-            placeholder={'请输入配送距离'}
-            value={model[field]}
-            onUpdate:value={val => (model[field] = val)}
-            v-slots={{ prefix: () => '大于', suffix: () => 'km' }}
-          ></NInput>
-        );
-      }
-    }
-  ],
-  labelWidth: 120,
-  layout: 'horizontal',
-  gridProps: {
-    cols: '1 xl:4 s:1 l:3',
-    itemResponsive: true
-  },
-  collapsedRows: 1,
-  showActionButtonGroup: false
-});
-
-function close() {
-  tabStore.removeTab(tabStore.activeTabId);
-}
-
-async function save() {
-  await validate();
-  const form = getFieldsValue();
-  console.log(form);
-}
-</script>
-
-<template>
-  <LayoutTable>
-    <NCard
-      title="分单配置(企业用户才有分单规则,C端用户只走配送,B端用户只走物流)"
-      :bordered="false"
-      size="small"
-      segmented
-      class="card-wrapper"
-    >
-      <BasicForm @register-form="registerForm"></BasicForm>
-      <template #footer>
-        <NSpace justify="end">
-          <NButton size="small" @click="close">关闭</NButton>
-          <NButton type="primary" size="small" @click="save">保存</NButton>
-        </NSpace>
-      </template>
-    </NCard>
-  </LayoutTable>
-</template>
-
-<style scoped></style>

+ 1 - 1
src/views/delivery/after-sales-order/order-modal.vue

@@ -56,7 +56,7 @@ function getImgFils() {
               </div>
             </div>
           </NTag>
-          <NTag>申请人: {{ orderInfo.receiver }} | 申请时间:{{ orderInfo.applyTime }}</NTag>
+          <NTag>申请人: {{ orderInfo.receiver || '---' }} | 申请时间:{{ orderInfo.applyTime }}</NTag>
         </NFlex>
         <NFlex vertical>
           <div class="text-16px font-semibold">

+ 1 - 1
src/views/delivery/normal-order/component/normal-modal.vue

@@ -194,7 +194,7 @@ function handleCopy() {
               </NTr>
               <NTr>
                 <NTd>积分</NTd>
-                <NTd>{{ orderInfo.offsetPoints || 0 }}</NTd>
+                <NTd>-{{ (Number(orderInfo.offsetPoints) / 100).toFixed(2) || 0 }}</NTd>
               </NTr>
               <NTr>
                 <NTd v-if="orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY">需付款</NTd>

+ 2 - 2
src/views/goods/store-goods/index.vue

@@ -29,7 +29,7 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
     key: 'skuName',
     title: '商品信息',
     align: 'left',
-    width: 300,
+    width: 400,
     fixed: 'left',
     render: row => {
       if (!row.sku) {
@@ -50,7 +50,7 @@ const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
             <div class={'text-gray'}>外部商品编码:{row.sku.skuCode || '--'} </div>
             <div class={'text-gray'}>条形码:{row.sku.modelId || '--'} </div>
             <div class={'text-gray'}>
-              重量/规格/单位:{row.sku.weight || '--'} / {row.sku.weightUnit || '--'} / {row.sku.weightUnit || '--'}
+              重量/规格/单位:{row.sku.weight || '--'} / {row.sku.spec || '--'} / {row.sku.weightUnit || '--'}
             </div>
           </div>
         </div>