feat(passport): 支持邮箱和用户ID登录合并账号登录

- LoginParam 接口新增 email 和 userId 字段
- 新增 loginByEmail 和 loginByUserId 接口调用,逻辑与 login 类似
- 登录页账号输入框改为 account,支持输入邮箱或用户ID
- 提交时根据账号格式(邮箱或纯数字)调用对应登录接口
- 校验规则改为校验 account 字段,格式不符时提示错误
- 手机号短信登录改用 loginBySuperAdminSms 接口替代 loginBySms
- 登录成功后保存租户ID和用户ID至 localStorage
- 优化登录页相关导入及逻辑,提升登录体验
This commit is contained in:
2026-07-18 17:00:39 +08:00
parent bef50c2f26
commit 2037b0699a
5 changed files with 259 additions and 11 deletions

View File

@@ -0,0 +1,40 @@
# 2026-07-18 工作日志
## 手机号登录改用 loginBySuperAdminSms 接口
### 改动文件
1. `src/api/passport/login/index.ts`
- 新增 `loginBySuperAdminSms()` 方法,调用 `/loginBySuperAdminSms` 接口
- 保留原有 `loginBySms()` 方法(其他页面如 register/dealer 仍在使用)
- 新方法逻辑与 `loginBySms` 一致:成功后 setToken + 存 TenantId/UserId
2. `src/views/passport/login/index.vue`
- import 替换:`loginBySms``loginBySuperAdminSms`
- `onLoginBySms()` 函数中调用替换:`loginBySms(form)``loginBySuperAdminSms(form)`
- 多租户选择逻辑(`listAdminsByPhoneAll`)保持不变
### 注意
- 仅改了管理后台登录页注册页面register/dealer仍用 `loginBySms`
## 账号登录合并邮箱/用户ID登录
### 需求
账号登录输入框同时支持「邮箱」和「用户ID」邮箱 → `https://server.websoft.top/api/loginByEmail`,纯数字 → `https://server.websoft.top/api/loginByUserId`
### 改动文件
1. `src/api/passport/login/model/index.ts`
- `LoginParam` 新增 `email?: string``userId?: string | number`
2. `src/api/passport/login/index.ts`
- 新增 `loginByEmail()` / `loginByUserId()`,逻辑同 `login()`setToken + 存 TenantId/UserId
3. `src/views/passport/login/index.vue`
- 表单字段 `userId``account`(新增 `LoginForm = User & { account?: string }` 类型)
- 输入框 placeholder 改为「邮箱 / 用户ID」form-item name 改为 `account`
- 校验规则 `userId``account`
- `submit()` 用正则判断邮箱(`/^[^\s@]+@[^\s@]+\.[^\s@]+$/`) / 纯数字(`/^\d+$/`)路由到对应接口格式不符提示「请输入正确的邮箱或用户ID」
- 移除未使用的 `login` 导入
### 注意
- 外部接口用绝对 URL`https://server.websoft.top/api/...`),未走 SERVER_API_URL 代理
- `vue-tsc` 全量检查仍有大量历史错误ByteMdEditor、shopActivity 等),本次改动无新增错误

View File

@@ -31,6 +31,48 @@ export async function login(data: LoginParam) {
return Promise.reject(new Error(res.data.message)); return Promise.reject(new Error(res.data.message));
} }
/**
* 邮箱登录
*/
export async function loginByEmail(data: LoginParam) {
const res = await request.post<ApiResult<LoginResult>>(
'https://server.websoft.top/api/loginByEmail',
data
);
if (res.data.code === 0) {
setToken(res.data.data?.access_token, data.remember);
if (res.data.data?.user) {
const user = res.data.data?.user;
localStorage.setItem('TenantId', String(user.tenantId));
localStorage.setItem('UserId', String(user.userId));
}
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 用户ID登录
*/
export async function loginByUserId(data: LoginParam) {
const res = await request.post<ApiResult<LoginResult>>(
'https://server.websoft.top/api/loginByUserId',
data
);
if (res.data.code === 0) {
setToken(res.data.data?.access_token, data.remember);
if (res.data.data?.user) {
const user = res.data.data?.user;
localStorage.setItem('TenantId', String(user.tenantId));
localStorage.setItem('UserId', String(user.userId));
}
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/** /**
* 获取验证码 * 获取验证码
*/ */
@@ -62,6 +104,27 @@ export async function loginBySms(data: LoginParam) {
return Promise.reject(new Error(res.data.message)); return Promise.reject(new Error(res.data.message));
} }
/**
* 超管手机号短信登录
*/
export async function loginBySuperAdminSms(data: LoginParam) {
const res = await request.post<ApiResult<LoginResult>>(
SERVER_API_URL + '/loginBySuperAdminSms',
data
);
if (res.data.code === 0) {
setToken(res.data.data?.access_token, data.remember);
if (res.data.data?.user) {
const user = res.data.data?.user;
localStorage.setItem('TenantId', String(user.tenantId));
localStorage.setItem('UserId', String(user.userId));
}
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/** /**
* 发送短信验证码 * 发送短信验证码
*/ */

View File

@@ -5,6 +5,10 @@ import type { User } from '@/api/system/user/model';
export interface LoginParam { export interface LoginParam {
// 账号 // 账号
username?: string; username?: string;
// 邮箱
email?: string;
// 用户ID
userId?: string | number;
// 密码 // 密码
password?: string; password?: string;
// 租户id // 租户id

View File

@@ -77,12 +77,12 @@
<!-- </template>--> <!-- </template>-->
<!-- </a-input>--> <!-- </a-input>-->
<!-- </a-form-item>--> <!-- </a-form-item>-->
<a-form-item name="username"> <a-form-item name="account">
<a-input <a-input
allow-clear allow-clear
size="large" size="large"
v-model:value="form.userId" v-model:value="form.account"
:placeholder="`用户ID`" placeholder="邮箱 / 用户ID"
> >
<template #prefix> <template #prefix>
<UserOutlined /> <UserOutlined />
@@ -278,7 +278,12 @@
RightOutlined RightOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';
import { goHomeRoute, cleanPageTabs } from '@/utils/page-tab-util'; import { goHomeRoute, cleanPageTabs } from '@/utils/page-tab-util';
import { login, loginBySms, getCaptcha } from '@/api/passport/login'; import {
loginBySuperAdminSms,
getCaptcha,
loginByEmail,
loginByUserId
} from '@/api/passport/login';
import QrLogin from '@/components/QrLogin/index.vue'; import QrLogin from '@/components/QrLogin/index.vue';
import { User } from '@/api/system/user/model'; import { User } from '@/api/system/user/model';
@@ -346,8 +351,10 @@
console.warn('获取网站配置失败,使用默认配置:', e.message); console.warn('获取网站配置失败,使用默认配置:', e.message);
} }
}; };
const { form } = useFormData<User>({ type LoginForm = User & { account?: string };
userId: undefined,
const { form } = useFormData<LoginForm>({
account: '',
username: '', username: '',
phone: '', phone: '',
password: '', password: '',
@@ -383,7 +390,7 @@
// 表单验证规则 // 表单验证规则
const rules = reactive({ const rules = reactive({
userId: [ account: [
{ {
required: true, required: true,
message: t('login.username'), message: t('login.username'),
@@ -479,7 +486,7 @@
.then(() => { .then(() => {
loading.value = true; loading.value = true;
form.code = form.smsCode?.toLowerCase(); form.code = form.smsCode?.toLowerCase();
loginBySms(form) loginBySuperAdminSms(form)
.then((msg) => { .then((msg) => {
if (msg == '请选择登录用户') { if (msg == '请选择登录用户') {
showSelectLoginUser.value = true; showSelectLoginUser.value = true;
@@ -524,10 +531,25 @@
// changeCaptcha(); // changeCaptcha();
// return; // return;
// } // }
const account = (form.account || '').trim();
// 邮箱格式判断
const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(account);
// 纯数字判断用户ID
const isPureNumber = /^\d+$/.test(account);
if (!isEmail && !isPureNumber) {
message.error('请输入正确的邮箱或用户ID');
return;
}
loading.value = true; loading.value = true;
form.code = form.code?.toLowerCase(); const payload = {
form.phone = undefined; password: form.password,
login(form) code: form.code?.toLowerCase(),
remember: form.remember
};
const loginApi = isEmail
? loginByEmail({ ...payload, email: account })
: loginByUserId({ ...payload, userId: account });
loginApi
.then((msg) => { .then((msg) => {
if (msg == '请选择登录用户') { if (msg == '请选择登录用户') {
showSelectLoginUser.value = true; showSelectLoginUser.value = true;

View File

@@ -0,0 +1,119 @@
=========================================================================
2026-07-17 今日改动问题点总结
=========================================================================
【一】管理后台guilixu-admin
1. 发货弹窗新增「发货门店」「配送店员」选择功能
- 文件src/views/shop/shopOrder/components/deliveryModal.vue
- 新增发货门店下拉(复用 listShopStore选中后自动回填
发货人/电话/地址
- 商家送货(deliveryType=2)新增配送店员二级联动下拉
- 新增校验:发货门店必填(deliveryType≠1)、配送店员必填(deliveryType=2)
- 提交时附带 sendStoreId / deliveryUserId
2. 发货弹窗文案优化
- 文件src/views/shop/shopOrder/components/deliveryModal.vue
- 「发货门店」标签动态化:快递配送→发货门店,商家送货→配送门店
- 「发货人」标签动态化:快递配送→寄件人,商家送货→发货人
- 提示文案、验证规则文案同步动态化
- 快递配送时增加"寄件人信息将同步至快递面单"说明
3. 订单模型字段补充
- 文件src/api/shop/shopOrder/model/index.ts
- 新增 sendStoreId、deliveryUserId 字段
4. 订单详情页展示发货门店/配送店员
- 文件src/views/shop/shopOrder/components/orderInfo.vue
- 发货信息卡片增加「发货门店」「配送店员」展示
- 支付状态标签新增「已发货待收款」(payType=9 && payStatus=0 && deliveryStatus=20)
- 步骤条逻辑:线下付款未付款但已发货时显示「下单→待收款→已发货」
5. 线下付款先发货后结款流程
- 文件src/views/shop/shopOrder/index.vue
- 线下付款未付款订单按发货状态区分操作按钮:
· deliveryStatus=10显示「确认收款」+「发货」+「关闭」
· deliveryStatus=20仅显示「确认收款」
- 文件src/views/shop/shopOrder/components/OfflinePaymentModal.vue
- 新增 deliveryStatus 字段及动态提示文案
- 成功消息动态化:已发货→「已自动完成」,未发货→「已进入待发货状态」
6. 配送方式排序调整
- 文件src/views/shop/shopOrder/components/deliveryModal.vue
- radio 顺序改为:快递配送→商家送货→无需发货
-------------------------------------------------------------------------
【二】后端 Javaguilixu-java
1. shop_order 主表新增字段
- ShopOrder.java新增 sendStoreId、deliveryUserId 持久化字段
及 sendStoreName、deliveryUserName 虚拟展示字段
- ShopOrderMapper.xmlLEFT JOIN shop_store / shop_store_user 联带名称
- SQLALTER TABLE shop_order ADD send_store_id INT, delivery_user_id INT
2. shop_order_delivery 发货单表新增字段
- ShopOrderDelivery.java新增 sendStoreId、deliveryUserId
- ShopOrderController.update():发货写入分支(无需物流/实物快递/补录运单号)
均 setSendStoreId / setDeliveryUserId
- SQLALTER TABLE shop_order_delivery ADD send_store_id INT, delivery_user_id INT
3. 线下付款确认收款逻辑调整
- ShopOrderServiceImpl.confirmOfflinePayment():移除订单状态=0约束
允许已发货订单确认收款;已发货(deliveryStatus=20)时确认后自动完成订单
- ShopOrderController / ShopOrderService更新接口描述和成功消息
-------------------------------------------------------------------------
【三】商家端小程序xinlong-shop-taro
1. 修复 storeId=0 导致发货人员列表为空的 Bug
- 文件src/pages/store/orders/index.tsx
- 问题根因openShipModal 调 listShopStoreUser() 未传 storeId(默认0)
- 修复:先 getMyClerk() 取 storeId再 listShopStoreUser({storeId})
- 默认选中当前登录人对应的店员
2. 修复订单详情页配送方式判断逻辑
- 文件src/pages/order/detail.tsx
- 问题:原 isExpress = deliveryType === 0 || undefined无法区分商家送货
- 修复isExpress 改为 deliveryType === 0 || 2 || undefined
- 新增 DELIVERY_TYPE_MAP0=快递配送, 1=自提, 2=商家送货
- 收货信息卡片:商家送货显示🛵+配送门店名,快递配送显示📦
- 订单信息区新增「配送方式」字段展示
3. 支持线下付款先发货后结款
- 文件src/pages/store/orders/index.tsx
- getStatusText():新增「已发货待收款」状态
- getOrderActions():线下付款未付款(payType=9)也能显示发货按钮
- OP_DESC确认收款描述移除"订单将进入待发货状态"
-------------------------------------------------------------------------
【四】跨项目误改纠正(教训记录)
1. 误将商家端功能改到 guilixu-taro用户端
- 错误改动useClerk 全局上下文、订单详情 deliveryType 修复
- 已用 git checkout 还原 guilixu-taro 的 5 个跟踪文件
- 已删除 guilixu-taro 新建的 2 个文件(ClerkContext.tsx / useClerk.ts)
- 正确项目xinlong-shop-taro商家端
2. 教训:跨项目改动前,先在多个候选项目里确认"哪个项目有该功能源码"
商家端发货/门店/订单 → xinlong-shop-taro
用户端订单详情等 → guilixu-taro
=========================================================================
今日 Git 提交记录
=========================================================================
bef50c2 feat(order): 支持线下付款先发货后结款流程
57be388 fix(xinlong-shop-taro): 修复订单详情页配送方式判断逻辑
bd814d0 feat(shop): 优化发货弹窗文案及修复小程序配送方式判断
3edbb13 fix(orders): 修正发货功能关联的项目错误导致 storeId 为 0
b406973 feat(store): 修正 storeId 获取并新增发货人员选择功能
2745f4b feat(shopOrder): 增加发货门店与配送店员选择功能
e9249c9 feat(shopOrder): 增加发货门店与配送店员选择功能
6b57dd2 fix(shopOrder): 修正确认收货状态码
=========================================================================
生成时间2026-07-17 18:18
=========================================================================