Compare commits

..

No commits in common. "5eb7ae6f0000e996b26ef51a58636acf6fc689c1" and "f3451a3357c3461be4edde2744f402bdbbe764f6" have entirely different histories.

13 changed files with 214 additions and 926 deletions

View File

@ -1,104 +0,0 @@
import { http } from "@/utils/http";
export interface Ab98UserDTO {
/** 主键ID */
ab98UserId?: number;
/** openid */
openid?: string;
/** 汇邦云用户唯一ID */
userid?: string;
/** 真实姓名 */
name?: string;
/** 手机号码 */
tel?: string;
/** 身份证号码 */
idnum?: string;
/** 性别(男 女) */
sex?: string;
/** 人脸照片地址 */
faceImg?: string;
/** 身份证正面地址 */
idcardFront?: string;
/** 身份证背面地址 */
idcardBack?: string;
/** 身份证登记地址 */
address?: string;
/** 是否已注册0未注册 1已注册 */
registered?: boolean;
}
export interface Ab98UserDetailDTO {
/** 主键ID */
ab98UserId?: number;
/** openid */
openid?: string;
/** 汇邦云用户唯一ID */
userid?: string;
/** 真实姓名 */
name?: string;
/** 手机号码 */
tel?: string;
/** 身份证号码 */
idnum?: string;
/** 性别(男 女) */
sex?: string;
/** 人脸照片地址 */
faceImg?: string;
/** 身份证正面地址 */
idcardFront?: string;
/** 身份证背面地址 */
idcardBack?: string;
/** 身份证登记地址 */
address?: string;
/** 是否已注册0未注册 1已注册 */
registered?: boolean;
createTime?: string;
}
export interface Ab98UserQuery extends BasePageQuery {
/** 真实姓名 */
name?: string;
/** 手机号码 */
tel?: string;
/** 身份证号码 */
idnum?: string;
}
export interface AddAb98UserCommand {
/** openid */
openid?: string;
/** 汇邦云用户唯一ID */
userid?: string;
/** 真实姓名 */
name?: string;
/** 手机号码 */
tel?: string;
/** 身份证号码 */
idnum?: string;
/** 性别(男 女) */
sex?: string;
}
export interface UpdateAb98UserCommand extends AddAb98UserCommand {
/** 主键ID */
ab98UserId: number;
}
export const getAb98UserListApi = (params: Ab98UserQuery) => {
return http.request<ResponseData<PageDTO<Ab98UserDTO>>>("get", "/ab98/users", { params });
};
export const addAb98UserApi = (data: AddAb98UserCommand) => {
return http.request<ResponseData<void>>("post", "/ab98/users", { data });
};
export const updateAb98UserApi = (id: number, data: UpdateAb98UserCommand) => {
return http.request<ResponseData<void>>("put", `/ab98/users/${id}`, { data });
};
export const deleteAb98UserApi = (ids: number[]) => {
return http.request<ResponseData<void>>("delete", `/ab98/users/${ids.join(',')}`);
};
export const getAb98UserDetailApi = (id: number) => {
return http.request<ResponseData<Ab98UserDetailDTO>>("get", `/ab98/users/detail/${id}`);
};

View File

@ -3,12 +3,6 @@ import { http } from "@/utils/http";
export interface OrderQuery extends BasePageQuery { export interface OrderQuery extends BasePageQuery {
/** 订单编号 */ /** 订单编号 */
orderId?: number; orderId?: number;
/**
* openid
*/
openid?: string;
/** 柜机id */
cabinetId?: number;
/** 格口id */ /** 格口id */
cellId?: number; cellId?: number;
/** /**

View File

@ -15,14 +15,6 @@ export default {
meta: { meta: {
title: "个人中心" title: "个人中心"
} }
},
{
path: "/user/ab98/detail",
name: "ab98Detail",
component: () => import("@/views/user/ab98/detail.vue"),
meta: {
title: "会员详情"
}
} }
] ]
} as RouteConfigsTable; } as RouteConfigsTable;

View File

@ -175,7 +175,3 @@
box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgb(69 98 155 / 12%); box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgb(69 98 155 / 12%);
} }
} }
.el-card.is-always-shadow {
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.04)!important;
}

View File

@ -4,7 +4,6 @@ import { PureTableBar } from "@/components/RePureTableBar";
import { onBeforeRouteUpdate, useRoute } from "vue-router"; import { onBeforeRouteUpdate, useRoute } from "vue-router";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { getCabinetCellList, deleteCabinetCell, CabinetCellDTO } from "@/api/cabinet/cabinet-cell"; import { getCabinetCellList, deleteCabinetCell, CabinetCellDTO } from "@/api/cabinet/cabinet-cell";
import { allCabinets, SmartCabinetDTO } from "@/api/cabinet/smart-cabinet";
import EditPen from "@iconify-icons/ep/edit-pen"; import EditPen from "@iconify-icons/ep/edit-pen";
import Delete from "@iconify-icons/ep/delete"; import Delete from "@iconify-icons/ep/delete";
import AddFill from "@iconify-icons/ri/add-circle-line"; import AddFill from "@iconify-icons/ri/add-circle-line";
@ -15,56 +14,39 @@ import CellEditModal from "./cell-edit-modal.vue";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { on } from "events"; import { on } from "events";
//
defineOptions({ defineOptions({
name: "CabinetCell" // name: "CabinetCell"
}); });
//
const formRef = ref(); const formRef = ref();
//
const tableRef = ref(); const tableRef = ref();
//
const modalVisible = ref(false); const modalVisible = ref(false);
//
const searchFormParams = ref({ const searchFormParams = ref({
cabinetId: null, // ID cabinetId: null,
cellNo: null, // cellNo: null,
cellType: null // cellType: null
}); });
//
const pagination = ref({ const pagination = ref({
pageSize: 10, // pageSize: 10,
currentPage: 1, // currentPage: 1,
total: 0 // total: 0
}); });
//
const loading = ref(false); const loading = ref(false);
//
const dataList = ref([]); const dataList = ref([]);
//
const multipleSelection = ref<number[]>([]); const multipleSelection = ref<number[]>([]);
//
const editVisible = ref(false); const editVisible = ref(false);
//
const currentRow = ref<CabinetCellDTO>(); const currentRow = ref<CabinetCellDTO>();
//
const route = useRoute(); const route = useRoute();
// onMounted(() => {
const cabinets = ref<SmartCabinetDTO[]>([]);
onMounted(async () => {
const { data } = await allCabinets();
cabinets.value = data;
if (route.query.cabinetId) { if (route.query.cabinetId) {
searchFormParams.value.cabinetId = Number(route.query.cabinetId); searchFormParams.value.cabinetId = Number(route.query.cabinetId);
}
getList(); getList();
}
}); });
onBeforeRouteUpdate(() => { onBeforeRouteUpdate(() => {
if (route.query.cabinetId) { if (route.query.cabinetId) {
@ -73,33 +55,24 @@ onBeforeRouteUpdate(() => {
} }
}); });
/**
* 获取单元格列表数据
* @returns {Promise<void>}
*/
const getList = async () => { const getList = async () => {
try { try {
loading.value = true; // loading.value = true;
// API
const { data } = await getCabinetCellList({ const { data } = await getCabinetCellList({
...searchFormParams.value, // ...searchFormParams.value,
pageSize: pagination.value.pageSize, // pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage // pageNum: pagination.value.currentPage
}); });
dataList.value = data.rows; // dataList.value = data.rows;
pagination.value.total = data.total; // pagination.value.total = data.total;
} finally { } finally {
loading.value = false; // loading.value = false;
} }
}; };
/**
* 搜索按钮点击事件
* 重置页码为第一页并重新获取数据
*/
const onSearch = () => { const onSearch = () => {
pagination.value.currentPage = 1; // pagination.value.currentPage = 1;
getList(); // getList();
}; };
const resetForm = () => { const resetForm = () => {
@ -117,18 +90,13 @@ const onCurrentChange = (val: number) => {
getList(); getList();
}; };
/**
* 删除单元格
* @param {CabinetCellDTO} row - 要删除的单元格数据
*/
const handleDelete = async (row: CabinetCellDTO) => { const handleDelete = async (row: CabinetCellDTO) => {
try { try {
// API
await deleteCabinetCell(row.cellId!.toString()); await deleteCabinetCell(row.cellId!.toString());
ElMessage.success("删除成功"); // ElMessage.success("删除成功");
getList(); // getList();
} catch (error) { } catch (error) {
console.error("删除失败", error); // console.error("删除失败", error);
} }
}; };
@ -160,11 +128,6 @@ const handleEdit = (row: CabinetCellDTO) => {
editVisible.value = true; editVisible.value = true;
}; };
/**
* 转换单元格类型为中文描述
* @param {number} cellType - 单元格类型编号
* @returns {string} 单元格类型中文描述
*/
const switchCellType = (cellType: number) => { const switchCellType = (cellType: number) => {
switch (cellType) { switch (cellType) {
case 1: case 1:
@ -183,24 +146,7 @@ const switchCellType = (cellType: number) => {
</script> </script>
<template> <template>
<div class="main flex"> <div class="main">
<!-- 左侧柜机列表 -->
<div class="w-[200px] pr-4 border-r h-full left-list">
<div class="text-lg font-bold mb-4 px-2">柜机列表</div>
<div class="h-[calc(100vh-180px)] overflow-y-auto">
<div class="cabinet-list">
<div v-for="cabinet in cabinets" :key="cabinet.cabinetId"
class="cabinet-item p-3 mb-2 cursor-pointer rounded hover:bg-gray-100 transition-colors"
:class="{ 'bg-blue-50': searchFormParams.cabinetId === cabinet.cabinetId }"
@click="searchFormParams.cabinetId = cabinet.cabinetId; onSearch()">
{{ cabinet.cabinetName }}
</div>
</div>
</div>
</div>
<!-- 右侧内容 -->
<div class="flex-1 pl-4">
<el-form ref="formRef" :inline="true" :model="searchFormParams" <el-form ref="formRef" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"> class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]">
<el-form-item label="柜体ID" prop="cabinetId"> <el-form-item label="柜体ID" prop="cabinetId">
@ -283,20 +229,6 @@ const switchCellType = (cellType: number) => {
@refresh="getList" /> @refresh="getList" />
<cell-edit-modal v-model:visible="editVisible" :row="currentRow" @refresh="getList" /> <cell-edit-modal v-model:visible="editVisible" :row="currentRow" @refresh="getList" />
</div> </div>
</div>
</template> </template>
<style lang="scss" scoped> <style scoped></style>
.flex {
display: flex;
}
.border-r {
border-right: 1px solid #ebeef5;
}
.left-list {
background: #FFFFFF;
padding: 15px;
}
</style>

View File

@ -111,7 +111,6 @@ getList();
<PureTableBar title="格口开启记录" @refresh="getList"> <PureTableBar title="格口开启记录" @refresh="getList">
<el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="operationId" border> <el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="operationId" border>
<el-table-column label="操作ID" prop="operationId" width="120" /> <el-table-column label="操作ID" prop="operationId" width="120" />
<el-table-column label="格口ID" prop="cellId" width="120" />
<el-table-column label="操作人" prop="name" width="120" /> <el-table-column label="操作人" prop="name" width="120" />
<el-table-column label="手机号" prop="mobile" width="120" /> <el-table-column label="手机号" prop="mobile" width="120" />
<el-table-column label="商品名称" prop="goodsName" width="180" /> <el-table-column label="商品名称" prop="goodsName" width="180" />

View File

@ -12,7 +12,6 @@ import Qrcode from "@iconify-icons/ep/iphone";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import ShopFormModal from "./shop-form-modal.vue"; import ShopFormModal from "./shop-form-modal.vue";
import ReQrcode from "@/components/ReQrcode"; import ReQrcode from "@/components/ReQrcode";
import { copyTextToClipboard } from "@pureadmin/utils";
defineOptions({ defineOptions({
name: "Shop" name: "Shop"
@ -124,12 +123,6 @@ const showQrCode = (shopId: number) => {
qrVisible.value = true; qrVisible.value = true;
}; };
const copyLink = () => {
const url = `http://wxshop.ab98.cn/shop-api/api/shop/wechatAuth?shopId=${currentShopId.value}`;
const success = copyTextToClipboard(url);
success ? ElMessage.success('链接复制成功') : ElMessage.error('复制失败,请手动复制');
};
getList(); getList();
</script> </script>
@ -195,9 +188,6 @@ getList();
<ReQrcode :text="`http://wxshop.ab98.cn/shop-api/api/shop/wechatAuth?shopId=${currentShopId}`" <ReQrcode :text="`http://wxshop.ab98.cn/shop-api/api/shop/wechatAuth?shopId=${currentShopId}`"
:options="{ width: 200 }" /> :options="{ width: 200 }" />
<div class="mt-2 text-sm text-gray-500">微信扫码访问</div> <div class="mt-2 text-sm text-gray-500">微信扫码访问</div>
<el-button class="mt-2" type="primary" size="small" @click="copyLink">
复制链接
</el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>

View File

@ -199,7 +199,8 @@ getList();
<el-button type="primary" link :icon="useRenderIcon(EditPen)" @click="handleEdit(row)"> <el-button type="primary" link :icon="useRenderIcon(EditPen)" @click="handleEdit(row)">
编辑 编辑
</el-button> </el-button>
<el-button type="warning" link :icon="useRenderIcon(EditPen)" @click="goCellManagement(row)"> <el-button type="warning" link :icon="useRenderIcon('fluent:cell-phone-arrow-right-20-regular')"
@click="goCellManagement(row)">
格口 格口
</el-button> </el-button>
<el-button type="warning" link :icon="useRenderIcon('ant-design:gateway-outlined')" <el-button type="warning" link :icon="useRenderIcon('ant-design:gateway-outlined')"

View File

@ -261,7 +261,6 @@ const handleClearGoods = async (row: CabinetCellDTO) => {
<el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="cellId" <el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="cellId"
@selection-change="handleSelectionChange" border> @selection-change="handleSelectionChange" border>
<el-table-column label="格口ID" prop="cellId" width="80" /> <el-table-column label="格口ID" prop="cellId" width="80" />
<el-table-column label="格口号" prop="cellNo" width="80" />
<el-table-column label="商品图片" width="120"> <el-table-column label="商品图片" width="120">
<template #default="{ row }"> <template #default="{ row }">
<el-image :src="row.coverImg" :preview-src-list="[row.coverImg]" :z-index="9999" <el-image :src="row.coverImg" :preview-src-list="[row.coverImg]" :z-index="9999"

View File

@ -1,9 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, onMounted } from "vue"; import { ref, watch } from "vue";
import { PureTableBar } from "@/components/RePureTableBar"; import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { getOrderListApi, exportOrderExcelApi, type OrderDTO, OrderQuery } from "@/api/shop/order"; import { getOrderListApi, exportOrderExcelApi, type OrderDTO, OrderQuery } from "@/api/shop/order";
import { allCabinets, SmartCabinetDTO } from "@/api/cabinet/smart-cabinet";
import Search from "@iconify-icons/ep/search"; import Search from "@iconify-icons/ep/search";
import Refresh from "@iconify-icons/ep/refresh"; import Refresh from "@iconify-icons/ep/refresh";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
@ -16,10 +15,8 @@ const route = useRoute();
const formRef = ref(); const formRef = ref();
const tableRef = ref(); const tableRef = ref();
const cabinets = ref<SmartCabinetDTO[]>([]);
const searchFormParams = ref<OrderQuery>({ const searchFormParams = ref<OrderQuery>({
cabinetId: null,
orderId: null, orderId: null,
cellId: null, cellId: null,
status: null, status: null,
@ -39,11 +36,6 @@ const pagination = ref({
const loading = ref(false); const loading = ref(false);
const dataList = ref<OrderDTO[]>([]); const dataList = ref<OrderDTO[]>([]);
onMounted(async () => {
const { data } = await allCabinets();
cabinets.value = data;
});
const getList = async () => { const getList = async () => {
try { try {
loading.value = true; loading.value = true;
@ -115,19 +107,7 @@ getList();
</script> </script>
<template> <template>
<div class="main flex"> <div class="main">
<!-- 左侧柜机列表 -->
<div class="w-[200px] mr-4 bg-white rounded shadow p-4">
<div class="text-lg font-bold mb-4">柜机列表</div>
<div class="space-y-2">
<div v-for="cabinet in cabinets" :key="cabinet.cabinetId" class="p-2 rounded cursor-pointer hover:bg-gray-100"
:class="{ 'bg-blue-50': searchFormParams.cabinetId === cabinet.cabinetId }"
@click="searchFormParams.cabinetId = cabinet.cabinetId; onSearch()">
{{ cabinet.cabinetName }}
</div>
</div>
</div>
<div class="flex-1">
<el-form ref="formRef" :inline="true" :model="searchFormParams" <el-form ref="formRef" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"> class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]">
<!-- <el-form-item label="时间范围:"> <!-- <el-form-item label="时间范围:">
@ -247,7 +227,6 @@ getList();
@size-change="onSizeChange" @current-change="onCurrentChange" /> @size-change="onSizeChange" @current-change="onCurrentChange" />
</PureTableBar> </PureTableBar>
</div> </div>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@ -1,253 +0,0 @@
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import { useRoute } from "vue-router";
import { type Ab98UserDetailDTO, getAb98UserDetailApi } from "@/api/ab98/user";
import { getOrderListApi, type OrderDTO } from "@/api/shop/order";
defineOptions({
name: "Ab98UserDetail"
});
const route = useRoute();
const userInfo = ref<Ab98UserDetailDTO>({});
const loading = ref(false);
//
const basicInfo = ref({
registerTime: "2023-01-15",
lastLogin: "2023-06-20",
loginCount: 42,
device: "iPhone 13"
});
//
const orderRecords = ref<OrderDTO[]>([]);
const pagination = ref({
pageSize: 5,
currentPage: 1,
total: 0
});
const orderLoading = ref(false);
const activeTab = ref('basic');
async function fetchOrders() {
try {
orderLoading.value = true;
const { data } = await getOrderListApi({
openid: userInfo.value.openid,
pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage
});
orderRecords.value = data.rows;
pagination.value.total = data.total;
} finally {
orderLoading.value = false;
}
}
watch(activeTab, (newVal) => {
if (newVal === 'orders') {
fetchOrders();
}
});
async function fetchUserDetail() {
try {
loading.value = true;
const userId = route.query.id;
const { data } = await getAb98UserDetailApi(Number(userId));
userInfo.value = data;
} finally {
loading.value = false;
}
}
onMounted(() => {
fetchUserDetail();
});
</script>
<template>
<div class="detail-container">
<div class="flex-container">
<el-card class="user-info-card">
<div class="user-header">
<el-avatar :size="100" :src="userInfo.faceImg" fit="cover" shape="square">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="48" fill="#f5f5f5" stroke="#e0e0e0" stroke-width="1" />
<circle cx="50" cy="40" r="12" fill="#9e9e9e" />
<rect x="40" y="52" width="20" height="30" rx="2" fill="#9e9e9e" />
</svg>
</el-avatar>
<div class="user-name">{{ userInfo.name }}</div>
</div>
<el-divider />
<el-descriptions class="user-details" :column="1" border>
<el-descriptions-item label="性别">{{ userInfo.sex }}</el-descriptions-item>
<el-descriptions-item label="手机号">{{ userInfo.tel }}</el-descriptions-item>
<el-descriptions-item label="身份证号">{{ userInfo.idnum }}</el-descriptions-item>
<el-descriptions-item label="住址">{{ userInfo.address }}</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card class="info-card">
<div class="tab-header">
<el-tabs type="card" v-model="activeTab">
<el-tab-pane label="基础信息" name="basic"></el-tab-pane>
<el-tab-pane label="订单记录" name="orders"></el-tab-pane>
</el-tabs>
</div>
<el-descriptions class="info-details" v-if="activeTab === 'basic'" :column="2" border>
<el-descriptions-item label="会员ID">{{ userInfo.ab98UserId }}</el-descriptions-item>
<el-descriptions-item label="微信openid">{{ userInfo.openid }}</el-descriptions-item>
<el-descriptions-item label="注册时间">{{ userInfo.createTime }}</el-descriptions-item>
<el-descriptions-item label="最后登录">{{ basicInfo.lastLogin }}</el-descriptions-item>
<el-descriptions-item label="登录次数">{{ basicInfo.loginCount }}</el-descriptions-item>
<el-descriptions-item label="常用设备">{{ basicInfo.device }}</el-descriptions-item>
</el-descriptions>
<div class="info-details" v-if="activeTab === 'orders'">
<PureTableBar title="订单列表" @refresh="fetchOrders">
<el-table ref="tableRef" v-loading="orderLoading" :data="orderRecords" row-key="orderId" border>
<el-table-column label="订单ID" prop="orderId" width="120" />
<el-table-column label="商品名称" prop="goodsNames" width="180">
<template #default="{ row }">
<span v-if="row.goodsNames">
{{ row.goodsNames.split(',').join(', ') }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="商品封面" prop="coverImgs" width="100">
<template #default="{ row }">
<div v-if="row.coverImgs" class="flex gap-2">
<el-image v-for="(img, index) in row.coverImgs.split(',')" :key="index" :src="img"
:preview-src-list="row.coverImgs.split(',')" :z-index="9999" :preview-teleported="true"
:hide-on-click-modal="true" fit="cover" class="rounded" width="60" height="60" />
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="姓名" prop="name" width="120" />
<el-table-column label="手机号" prop="mobile" width="120" />
<el-table-column label="订单金额" prop="totalAmount" width="120">
<template #default="{ row }">{{ row.totalAmount }}</template>
</el-table-column>
<el-table-column label="订单状态" prop="status" width="120">
<template #default="{ row }">
<el-tag :type="row.status === 2 ? 'success' : row.status === 5 ? 'danger' : 'info'">
{{ { 1: '待付款', 2: '已付款', 3: '已发货', 4: '已完成', 5: '已取消' }[row.status] }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="支付状态" prop="payStatus" width="120">
<template #default="{ row }">
<el-tag :type="row.payStatus === 2 ? 'success' : 'info'">
{{ { 1: '未支付', 2: '已支付', 3: '退款中', 4: '已退款' }[row.payStatus] }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="120">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="支付时间" prop="payTime" width="180">
<template #default="{ row }">
{{ row.payTime ? new Date(row.payTime).toLocaleString() : '-' }}
</template>
</el-table-column>
</el-table>
<el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize"
:page-sizes="[5, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
@size-change="fetchOrders" @current-change="fetchOrders" />
</PureTableBar>
</div>
</el-card>
</div>
</div>
</template>
<style scoped lang="scss">
.detail-container {
display: flex;
flex-direction: column;
height: 100%;
.flex-container {
display: flex;
flex: 1;
gap: 20px;
min-height: 0;
.user-info-card {
width: 20%;
}
.info-card {
width: 80%;
}
}
.user-info-card,
.shop-info-card {
height: 100%;
min-height: 85vh;
}
.user-header {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
.user-name {
margin-top: 15px;
font-size: 20px;
font-weight: bold;
}
}
.tab-header {
margin-bottom: 20px;
}
.order-item {
margin-bottom: 20px;
padding: 10px;
background-color: #f9f9f9;
border-radius: 4px;
.order-id {
font-weight: bold;
margin-bottom: 8px;
}
.order-detail {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #666;
}
}
.detail-item {
margin: 15px 0;
font-size: 14px;
.label {
color: #606266;
margin-right: 10px;
}
.value {
color: #303133;
}
}
}
</style>

View File

@ -1,226 +0,0 @@
<script setup lang="ts">
import { onMounted, reactive, ref, watch } from "vue";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { getAb98UserListApi, type Ab98UserDTO, Ab98UserQuery } from "@/api/ab98/user";
import { type PaginationProps } from "@pureadmin/table";
import { CommonUtils } from "@/utils/common";
import Search from "@iconify-icons/ep/search";
import Refresh from "@iconify-icons/ep/refresh";
import View from "@iconify-icons/ep/view";
import { useRouter } from "vue-router";
defineOptions({
name: "Ab98User"
});
const router = useRouter();
const formRef = ref();
const searchFormParams = reactive<Ab98UserQuery>({
name: undefined,
tel: undefined,
idnum: undefined
});
const pageLoading = ref(false);
const dataList = ref<Ab98UserDTO[]>([]);
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 12,
currentPage: 1,
background: true
});
async function onSearch() {
pagination.currentPage = 1;
getList();
}
async function getList() {
CommonUtils.fillPaginationParams(searchFormParams, pagination);
pageLoading.value = true;
const { data } = await getAb98UserListApi(searchFormParams).finally(
() => {
pageLoading.value = false;
}
);
dataList.value = data.rows;
pagination.total = data.total;
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
const handleViewDetail = (row: any) => {
router.push({
path: '/user/ab98/detail',
query: {
id: row.ab98UserId
}
});
};
onMounted(() => {
getList();
})
</script>
<template>
<div class="main">
<div class="float-right w-full">
<el-form ref="formRef" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]">
<el-form-item label="姓名:" prop="name">
<el-input v-model="searchFormParams.name" placeholder="请输入" clearable class="!w-[160px]" />
</el-form-item>
<el-form-item label="手机号:" prop="tel">
<el-input v-model="searchFormParams.tel" placeholder="请输入" clearable class="!w-[160px]" />
</el-form-item>
<el-form-item label="身份证:" prop="idnum">
<el-input v-model="searchFormParams.idnum" placeholder="请输入" clearable class="!w-[160px]" />
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="useRenderIcon(Search)" :loading="pageLoading" @click="onSearch">
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
</el-form-item>
</el-form>
<div class="grid-container">
<el-row :gutter="20">
<el-col v-for="(item, index) in dataList" :key="item.ab98UserId" :xs="24" :sm="12" :md="8" :lg="6">
<el-card class="user-card" :body-style="{ padding: '8px 20px' }">
<div class="card-content">
<el-avatar :size="80" :src="item.faceImg" fit="cover" shape="square" class="avatar">
<template v-if="!item.faceImg">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="48" fill="#f5f5f5" stroke="#e0e0e0" stroke-width="1" />
<circle cx="50" cy="40" r="12" fill="#9e9e9e" />
<rect x="40" y="52" width="20" height="30" rx="2" fill="#9e9e9e" />
</svg>
</template>
</el-avatar>
<div class="user-info">
<div class="name">姓名{{ item.name }}</div>
<div class="gender">性别{{ item.sex === '男' ? '男' : item.sex === '女' ? '女' : '' }}</div>
<div class="tel">电话{{ item.tel }}</div>
</div>
</div>
<div class="idnum">身份证号{{ item.idnum }}</div>
<div class="address"> {{ item.address }}</div>
<el-divider class="divider" />
<el-button class="detail-btn" :icon="useRenderIcon(View)" @click="handleViewDetail(item)" />
</el-card>
</el-col>
</el-row>
<div class="pagination-wrapper">
<el-pagination background layout="prev, pager, next" :page-size="pagination.pageSize"
:total="pagination.total" v-model:current-page="pagination.currentPage" @current-change="getList"
@size-change="getList" />
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
:deep(.el-dropdown-menu__item i) {
margin: 0;
}
.search-form {
:deep(.el-form-item) {
margin-bottom: 12px;
}
}
.user-card {
margin-bottom: 20px;
min-height: 210px;
display: flex;
flex-direction: column;
justify-content: space-between;
.card-content {
flex: 1;
display: flex;
flex-direction: row;
margin: 15px 0px;
gap: 15px;
.avatar {
align-self: flex-start;
}
.user-info {
text-align: left;
flex: 1;
.name,
.gender,
.tel {
font-size: 14px;
color: #606266;
margin-bottom: 6px;
line-height: 1.5;
}
.name {
font-weight: 500;
color: #303133;
}
}
.idnum,
.address {
font-size: 13px;
color: #606266;
margin: 4px 0;
line-height: 1.5;
word-break: break-all;
}
}
.divider {
margin: 10px 0px;
}
.detail-btn {
width: 100%;
border: 0;
margin-top: auto;
padding: 12px 0;
}
}
.grid-container {
margin: 20px 0;
padding-bottom: 60px;
position: relative;
.el-row {
margin-bottom: -20px;
}
}
.pagination-wrapper {
position: relative;
background: var(--el-bg-color);
padding: 12px 12px;
margin-top: 20px;
text-align: center;
:deep(.el-pagination) {
margin: 0;
padding: 8px 0;
}
}
</style>

View File

@ -60,21 +60,10 @@ watch(
<el-col v-for="(item, index) in dataList" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6"> <el-col v-for="(item, index) in dataList" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6">
<el-card class="user-card"> <el-card class="user-card">
<div class="card-content"> <div class="card-content">
<el-avatar :size="60" :src="item.avatar" fit="cover" shape="square" class="avatar"> <el-avatar :size="60" :src="item.avatar" fit="cover" shape="square" class="avatar" />
<template v-if="!item.avatar">
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- 浅灰圆形背景 -->
<circle cx="50" cy="50" r="48" fill="#f5f5f5" stroke="#e0e0e0" stroke-width="1" />
<!-- 中灰人形图标 -->
<circle cx="50" cy="40" r="12" fill="#9e9e9e" />
<!-- 修改后的身体部分 - 矩形躯干 -->
<rect x="40" y="52" width="20" height="30" rx="2" fill="#9e9e9e" />
</svg>
</template>
</el-avatar>
<div class="user-info"> <div class="user-info">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.name }}</div>
<!-- <div class="gender">性别{{ item.gender === '1' ? '男' : item.gender === '2' ? '女' : '' }}</div> --> <div class="gender">性别{{ item.gender === '1' ? '男' : item.gender === '2' ? '女' : '' }}</div>
<div class="create-time">创建时间{{ item.createTimeStr }}</div> <div class="create-time">创建时间{{ item.createTimeStr }}</div>
<div class="balance">余额¥{{ item.balance?.toFixed(2) }}</div> <div class="balance">余额¥{{ item.balance?.toFixed(2) }}</div>
</div> </div>