feat(shop): 优化店铺功能模块界面和交互

- 修改提现页面状态标签文案为更准确的描述
- 在用户信息中添加ID显示并调整布局结构
- 简化支付信息显示为统一的商家转账标识
- 调整表格列配置,将用户ID改为订单号,新增收款方式列
- 修复行双击编辑功能被注释的问题
- 将礼品卡文本修正为礼品劵
- 配送员编辑页面增加用户和社区选择组件及密钥保护功能
- 身份证号显示增加掩码保护
- 配送员列表页面重新排列列顺序
- 菜单搜索组件关键词字段从keywords改为title
- 开发环境配置中注释掉API地址配置
This commit is contained in:
2026-01-31 18:57:15 +08:00
parent 8bc99512fc
commit 5090dd1d44
6 changed files with 176 additions and 97 deletions

View File

@@ -1,5 +1,5 @@
VITE_APP_NAME=后台管理(开发环境) VITE_APP_NAME=后台管理(开发环境)
VITE_API_URL=http://127.0.0.1:9200/api #VITE_API_URL=http://127.0.0.1:9200/api
#VITE_SERVER_API_URL=http://127.0.0.1:8000/api #VITE_SERVER_API_URL=http://127.0.0.1:8000/api

View File

@@ -25,41 +25,27 @@
>待审核</a-tag >待审核</a-tag
> >
<a-tag v-if="record.applyStatus === 20" color="success" <a-tag v-if="record.applyStatus === 20" color="success"
>审核通过</a-tag >转账成功</a-tag
> >
<a-tag v-if="record.applyStatus === 30" color="error">已驳回</a-tag> <a-tag v-if="record.applyStatus === 30" color="error">用户取消</a-tag>
<a-tag v-if="record.applyStatus === 40">已打款</a-tag> <a-tag v-if="record.applyStatus === 40">已打款</a-tag>
</template> </template>
<template v-if="column.key === 'userInfo'"> <template v-if="column.key === 'userInfo'">
<a-space> <a-space>
<a-avatar :src="record.avatar" /> <a-avatar :src="record.avatar" />
<div class="flex flex-col"> <div class="flex flex-col">
<span>{{ record.realName || '未实名认证' }}</span> <div>
<span class="text-gray-400">{{ record.phone }}</span> <span>{{ record.realName || '未实名认证' }}</span>
<span class="text-gray-400">ID{{ record.userId }}</span>
</div>
<div><span class="text-gray-400">{{ record.phone }}</span></div>
</div> </div>
</a-space> </a-space>
</template> </template>
<template v-if="column.key === 'paymentInfo'"> <template v-if="column.key === 'paymentInfo'">
<template v-if="record.payType === 10"> <template v-if="record.payType === 10">
<a-space direction="vertical"> <a-space direction="vertical">
<a-tag color="blue">微信</a-tag> <a-tag color="blue">商家转账</a-tag>
<span>{{ record.wechatName }}</span>
<span>{{ record.wechatName }}</span>
</a-space>
</template>
<template v-if="record.payType === 20">
<a-space direction="vertical">
<a-tag color="blue">支付宝</a-tag>
<span>{{ record.alipayName }}</span>
<span>{{ record.alipayAccount }}</span>
</a-space>
</template>
<template v-if="record.payType === 30">
<a-space direction="vertical">
<a-tag color="blue">银行卡</a-tag>
<span>{{ record.bankName }}</span>
<span>{{ record.bankAccount }}</span>
<span>{{ record.bankCard }}</span>
</a-space> </a-space>
</template> </template>
</template> </template>
@@ -186,26 +172,27 @@
// 表格列配置 // 表格列配置
const columns = ref<ColumnItem[]>([ const columns = ref<ColumnItem[]>([
{ {
title: '用户ID', title: '订单号',
dataIndex: 'userId', dataIndex: 'id',
key: 'userId', key: 'id',
align: 'center', align: 'center',
width: 90, width: 90,
fixed: 'left' fixed: 'left'
}, },
// {
// title: '用户ID',
// dataIndex: 'userId',
// key: 'userId',
// align: 'center',
// width: 90,
// fixed: 'left'
// },
{ {
title: '提现金额', title: '收款方式',
dataIndex: 'money', dataIndex: 'paymentInfo',
key: 'money', key: 'paymentInfo',
align: 'center', align: 'center',
width: 150, width: 180
customRender: ({ text }) => {
const amount = parseFloat(text || '0').toFixed(2);
return {
type: 'span',
children: `¥${amount}`
};
}
}, },
{ {
title: '用户信息', title: '用户信息',
@@ -213,9 +200,17 @@
key: 'userInfo' key: 'userInfo'
}, },
{ {
title: '收款信息', title: '转账金额',
dataIndex: 'paymentInfo', dataIndex: 'money',
key: 'paymentInfo' key: 'money',
align: 'center',
customRender: ({ text }) => {
const amount = parseFloat(text || '0').toFixed(2);
return {
type: 'span',
children: `¥${amount}`
};
}
}, },
// { // {
// title: '审核时间', // title: '审核时间',
@@ -247,7 +242,7 @@
key: 'comments' key: 'comments'
}, },
{ {
title: '申请状态', title: '状态',
dataIndex: 'applyStatus', dataIndex: 'applyStatus',
key: 'applyStatus', key: 'applyStatus',
align: 'center', align: 'center',
@@ -448,7 +443,7 @@
}, },
// 行双击事件 // 行双击事件
onDblclick: () => { onDblclick: () => {
openEdit(record); // openEdit(record);
} }
}; };
}; };

View File

@@ -19,7 +19,7 @@
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' } styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
" "
> >
<a-form-item label="礼品" name="name"> <a-form-item label="礼品" name="name">
<a-input <a-input
allow-clear allow-clear
placeholder="请输入礼品卡名称" placeholder="请输入礼品卡名称"

View File

@@ -20,26 +20,29 @@
" "
> >
<a-form-item label="选择用户" name="userId"> <a-form-item label="选择用户" name="userId">
<!-- SelectUser 组件本身不支持 v-model只通过 @done 回传选择结果 key 强制刷新回显 -->
<SelectUser <SelectUser
:key="String(form.userId ?? '') + selectedUserText"
:value="selectedUserText"
:placeholder="`选择用户`" :placeholder="`选择用户`"
v-model:value="form.userId"
@done="onChooseUser" @done="onChooseUser"
/> />
</a-form-item> </a-form-item>
<a-form-item label="配送点" name="dealerId"> <a-form-item label="配送点(小区)" name="dealerId">
<a-input <SelectCommunity
allow-clear :key="String(form.dealerId ?? '') + selectedCommunityText"
placeholder="请输入配送点ID(多选)" :value="selectedCommunityText"
v-model:value="form.dealerId" :placeholder="`选择小区`"
@done="onChooseCommunity"
/>
</a-form-item>
<a-form-item label="骑手编号" name="riderNo">
<a-input
allow-clear
placeholder="请输入骑手编号(可选)"
v-model:value="form.riderNo"
/> />
</a-form-item> </a-form-item>
<!-- <a-form-item label="骑手编号" name="riderNo">-->
<!-- <a-input-->
<!-- allow-clear-->
<!-- placeholder="请输入骑手编号(可选)"-->
<!-- v-model:value="form.riderNo"-->
<!-- />-->
<!-- </a-form-item>-->
<a-form-item label="姓名" name="realName"> <a-form-item label="姓名" name="realName">
<a-input <a-input
allow-clear allow-clear
@@ -54,26 +57,20 @@
v-model:value="form.mobile" v-model:value="form.mobile"
/> />
</a-form-item> </a-form-item>
<a-form-item label="头像" name="avatar"> <!-- <a-form-item label="头像" name="avatar">-->
<a-input <!-- <a-input-->
allow-clear <!-- allow-clear-->
placeholder="请输入头像" <!-- placeholder="请输入头像"-->
v-model:value="form.avatar" <!-- v-model:value="form.avatar"-->
/> <!-- />-->
</a-form-item> <!-- </a-form-item>-->
<a-form-item label="身份证号" name="idCardNo"> <a-form-item label="身份证号" name="idCardNo">
<a-input <a-input
allow-clear allow-clear
placeholder="请输入身份证号" placeholder="请输入身份证号"
v-model:value="form.idCardNo" :value="maskedIdCardNo"
/> />
</a-form-item> </a-form-item>
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">正常</a-radio>
<a-radio :value="1">禁用</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="接单状态" name="workStatus"> <a-form-item label="接单状态" name="workStatus">
<a-input <a-input
allow-clear allow-clear
@@ -147,22 +144,34 @@
v-model:value="form.sortNumber" v-model:value="form.sortNumber"
/> />
</a-form-item> </a-form-item>
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">正常</a-radio>
<a-radio :value="1">禁用</a-radio>
</a-radio-group>
</a-form-item>
</a-form> </a-form>
</ele-modal> </ele-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, watch } from 'vue'; import { computed, ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue'; import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro'; import { assignObject, uuid } from 'ele-admin-pro';
import { addShopStoreRider, updateShopStoreRider } from '@/api/shop/shopStoreRider'; import {
addShopStoreRider,
updateShopStoreRider
} from '@/api/shop/shopStoreRider';
import { ShopStoreRider } from '@/api/shop/shopStoreRider/model'; import { ShopStoreRider } from '@/api/shop/shopStoreRider/model';
import { getUser } from '@/api/system/user';
import { getShopCommunity } from '@/api/shop/shopCommunity';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types'; import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form'; import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model'; import { FileRecord } from '@/api/system/file/model';
import type { User } from '@/api/system/user/model'; import type { User } from '@/api/system/user/model';
import type { ShopCommunity } from '@/api/shop/shopCommunity/model';
// 是否是修改 // 是否是修改
const isUpdate = ref(false); const isUpdate = ref(false);
@@ -190,6 +199,8 @@
// 表格选中数据 // 表格选中数据
const formRef = ref<FormInstance | null>(null); const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]); const images = ref<ItemType[]>([]);
const selectedUserText = ref('');
const selectedCommunityText = ref('');
// 用户信息 // 用户信息
const form = reactive<ShopStoreRider>({ const form = reactive<ShopStoreRider>({
@@ -225,17 +236,33 @@
// 表单验证规则 // 表单验证规则
const rules = reactive({ const rules = reactive({
shopStoreRiderName: [ // userId: [
{ // {
required: true, // required: true,
type: 'string', // type: 'string',
message: '请填写配送员名称', // message: '请选择用户',
trigger: 'blur' // trigger: 'blur'
} // }
] // ],
// dealerId: [
// {
// required: true,
// type: 'string',
// message: '请选择配送点',
// trigger: 'blur'
// }
// ],
// realName: [
// {
// required: true,
// type: 'string',
// message: '请填写姓名',
// trigger: 'blur'
// }
// ],
}); });
const chooseImage = (data: FileRecord) => { const _chooseImage = (data: FileRecord) => {
images.value.push({ images.value.push({
uid: data.id, uid: data.id,
url: data.path, url: data.path,
@@ -244,13 +271,26 @@
form.avatar = data.path; form.avatar = data.path;
}; };
const onDeleteItem = (index: number) => { const _onDeleteItem = (index: number) => {
images.value.splice(index, 1); images.value.splice(index, 1);
form.avatar = ''; form.avatar = '';
}; };
const maskIdCard = (value?: string) => {
if (!value) return '';
const s = String(value).trim();
const startLen = Math.min(6, Math.max(0, s.length - 4));
const endLen = Math.min(4, s.length);
const starLen = Math.max(4, s.length - startLen - endLen);
if (s.length <= startLen + endLen) return s;
return `${s.slice(0, startLen)}${'*'.repeat(starLen)}${s.slice(-endLen)}`;
};
const maskedIdCardNo = computed(() => maskIdCard(form.idCardNo));
const onChooseUser = (user?: User) => { const onChooseUser = (user?: User) => {
if (!user) { if (!user) {
selectedUserText.value = '';
form.userId = undefined; form.userId = undefined;
return; return;
} }
@@ -259,6 +299,22 @@
form.mobile = user.phone ?? user.mobile; form.mobile = user.phone ?? user.mobile;
form.avatar = user.avatar ?? user.avatarUrl; form.avatar = user.avatar ?? user.avatarUrl;
form.idCardNo = user.idCard ?? user.idcard; form.idCardNo = user.idCard ?? user.idcard;
const name = user.realName ?? user.nickname ?? '';
const phone = user.phone ?? user.mobile ?? '';
selectedUserText.value = phone ? `${name}${phone}` : name;
};
const onChooseCommunity = (
community?: ShopCommunity & { index?: number }
) => {
if (!community) {
selectedCommunityText.value = '';
form.dealerId = undefined;
return;
}
form.dealerId = community.id;
selectedCommunityText.value = community.name ?? String(community.id ?? '');
}; };
const { resetFields } = useForm(form, rules); const { resetFields } = useForm(form, rules);
@@ -275,7 +331,9 @@
const formData = { const formData = {
...form ...form
}; };
const saveOrUpdate = isUpdate.value ? updateShopStoreRider : addShopStoreRider; const saveOrUpdate = isUpdate.value
? updateShopStoreRider
: addShopStoreRider;
saveOrUpdate(formData) saveOrUpdate(formData)
.then((msg) => { .then((msg) => {
loading.value = false; loading.value = false;
@@ -296,16 +354,47 @@
(visible) => { (visible) => {
if (visible) { if (visible) {
images.value = []; images.value = [];
selectedUserText.value = '';
selectedCommunityText.value = '';
if (props.data) { if (props.data) {
assignObject(form, props.data); assignObject(form, props.data);
if(props.data.avatar){ if (props.data.avatar) {
images.value.push({ images.value.push({
uid: uuid(), uid: uuid(),
url: props.data.avatar, url: props.data.avatar,
status: 'done' status: 'done'
}) });
} }
isUpdate.value = true; isUpdate.value = true;
// 回显展示文本(避免组件内部不响应 props.value 更新)
if (form.userId) {
const uid = form.userId;
getUser(form.userId)
.then((user) => {
if (form.userId !== uid) return;
const name = user.realName ?? user.nickname ?? '';
const phone = user.phone ?? user.mobile ?? '';
selectedUserText.value = phone ? `${name}${phone}` : name;
})
.catch(() => {
if (form.userId !== uid) return;
selectedUserText.value = String(form.userId ?? '');
});
}
if (form.dealerId) {
const dealerId = form.dealerId;
getShopCommunity(form.dealerId)
.then((community) => {
if (form.dealerId !== dealerId) return;
selectedCommunityText.value =
community.name ?? String(community.id ?? '');
})
.catch(() => {
if (form.dealerId !== dealerId) return;
selectedCommunityText.value = String(form.dealerId ?? '');
});
}
} else { } else {
isUpdate.value = false; isUpdate.value = false;
} }

View File

@@ -105,16 +105,6 @@
key: 'userId', key: 'userId',
width: 90 width: 90
}, },
{
title: '选择配送点',
dataIndex: 'dealerId',
key: 'dealerId'
},
{
title: '骑手编号',
dataIndex: 'riderNo',
key: 'riderNo'
},
{ {
title: '姓名', title: '姓名',
dataIndex: 'realName', dataIndex: 'realName',
@@ -135,6 +125,11 @@
dataIndex: 'idCardNo', dataIndex: 'idCardNo',
key: 'idCardNo' key: 'idCardNo'
}, },
{
title: '选择配送点',
dataIndex: 'dealerId',
key: 'dealerId'
},
// { // {
// title: '状态', // title: '状态',
// dataIndex: 'status', // dataIndex: 'status',

View File

@@ -5,9 +5,9 @@
<a-button type="dashed" @click="openImport">恢复</a-button> <a-button type="dashed" @click="openImport">恢复</a-button>
<a-input-search <a-input-search
allow-clear allow-clear
placeholder="请输入关键词搜索" placeholder="请输入菜单名称"
style="width: 240px" style="width: 240px"
v-model:value="where.keywords" v-model:value="where.title"
@search="reload" @search="reload"
/> />
<a-button type="text" @click="reset">重置</a-button> <a-button type="text" @click="reset">重置</a-button>