Compare commits

...

6 Commits

Author SHA1 Message Date
dzq aa9a89c5c5 feat(智能柜管理): 添加随机生成柜体名称功能
在编辑和新增智能柜的表单中添加随机名称按钮,从预定义的名称列表中随机选择一个作为柜体名称
2025-06-28 16:12:16 +08:00
dzq 73e9afceed feat(柜体管理): 添加格口价格字段及配置功能
在柜体管理模块中新增格口价格字段,支持在特定模式下配置格口价格。主要修改包括:
1. 在DTO和表单中添加cellPrice字段
2. 在编辑模态框中添加价格输入项
3. 根据shopInfo.mode显示不同的配置按钮
4. 在详情页中根据模式显示格口价格或商品价格
2025-06-26 11:40:11 +08:00
dzq fa5beaa423 feat(订单): 添加退款状态查询字段并移除重置按钮
在订单查询接口和页面中添加退款状态字段,支持按退款状态筛选订单
移除两个页面中的重置按钮以简化界面操作
2025-06-24 17:54:34 +08:00
dzq a1a67fac71 fix: 将"余额支付"统一修改为"借呗支付"
修改支付方式显示文本,将所有"余额支付"的引用统一更新为"借呗支付",保持系统支付方式描述的一致性
2025-06-24 15:56:28 +08:00
dzq 80dc7ecd58 feat(approvalCenter): 添加审批中心列表页功能及搜索过滤
- 在接口定义中添加handleStatus和searchStr字段支持搜索过滤
- 实现审批列表的数据加载、分页和搜索功能
- 添加表格展示及状态标签显示
- 实现不同菜单下的数据切换和加载
2025-06-24 15:45:26 +08:00
dzq 52f8cbff4a feat(shop): 添加商店列表API和审批中心页面
- 在shop模块中添加getShopListApi方法用于获取商店列表
- 在智能柜页面中增加商店选择功能
- 新增审批中心页面,包含申请类型展示和导航功能
2025-06-23 17:43:54 +08:00
16 changed files with 609 additions and 41 deletions

View File

@ -36,6 +36,8 @@ export interface CabinetCellDTO {
stock?: number;
/** 历史订单数量 */
orderCount?: number;
/** 商品价格 */
cellPrice?: number;
}
export interface AddCabinetCellCommand {

View File

@ -9,7 +9,7 @@ export interface SearchReturnApprovalQuery extends BasePageQuery {
/**
*
* @remarks
* wechat- | balance-
* wechat- | balance-
*/
paymentMethod?: string;
/**
@ -18,6 +18,18 @@ export interface SearchReturnApprovalQuery extends BasePageQuery {
* 0 1
*/
approvalType: number;
/**
*
* @remarks
* 0:待处理 1:已处理
*/
handleStatus?: number;
/**
*
* @remarks
*
*/
searchStr?: string;
}
/** 退货审批DTO */
@ -58,7 +70,7 @@ export interface ReturnApprovalDTO {
/**
*
* @remarks
* wechat- | balance-
* wechat- | balance-
*/
paymentMethod?: string;
}

View File

@ -37,9 +37,15 @@ export interface OrderQuery extends BasePageQuery {
/**
*
* @remarks
* wechat- | balance-
* wechat- | balance-
*/
paymentMethod?: string;
/**
* 退
* @remarks
* 0-退 | 1-退
*/
returnStatus?: number;
}
export interface OrderDTO {
@ -82,7 +88,7 @@ export interface OrderDTO {
/**
*
* @remarks
* wechat- | balance-
* wechat- | balance-
*/
paymentMethod?: string;
/** 支付时间 */

View File

@ -98,6 +98,13 @@ export const getShopList = (params?: ShopQuery) => {
});
};
/** 获取商店列表 */
export const getShopListApi = (params?: ShopQuery) => {
return http.request<ResponseData<ShopDTO[]>>('get', '/shop/shops/list', {
params
});
};
/** 获取商店详情 */
export const getShopById = (id: number) => {
return http.request<ResponseData<ShopDTO>>('get', `/shop/shops/${id}`);

View File

@ -0,0 +1 @@
export const cabinetNames = ["智云柜", "慧科柜", "极客柜", "智能立方", "云枢柜", "科芯柜", "星轨柜", "元储柜", "未来舱", "智核柜", "光年柜", "量子存", "星际柜", "智链柜", "幻速柜", "数智匣", "智擎柜", "元界柜", "熵减柜", "智熵柜", "科创舱", "智核舱", "云熵柜", "星曜柜", "智璇柜", "科曜柜", "元枢柜", "智旋柜", "星熵柜", "科旋柜", "速存柜", "易取柜", "瞬存柜", "秒取柜", "速易柜", "捷存柜", "闪拿柜", "疾运柜", "瞬达柜", "快易柜", "速捷柜", "瞬通柜", "秒存柜", "闪运柜", "疾取柜", "速达柜", "快存柜", "捷取柜", "瞬捷柜", "秒运柜", "闪存柜", "疾通柜", "速捷仓", "快易仓", "瞬取仓", "秒捷柜", "闪易柜", "疾存柜", "速通柜", "快捷柜", "安信柜", "稳存柜", "固密柜", "保信仓", "安盾柜", "稳密柜", "固存柜", "保捷柜", "安垒柜", "稳捷柜", "固信柜", "保速柜", "安固柜", "稳信柜", "固捷柜", "保仓柜", "安捷柜", "稳仓柜", "固速柜", "保密柜", "安速柜", "稳固柜", "固仓柜", "保捷仓", "安密柜", "稳速柜", "固安柜", "保固柜", "安仓柜", "稳固仓", "生活智柜", "家居存", "社区宝", "邻里仓", "生活匣", "家居智柜", "社区存", "邻里柜", "生活仓", "家居匣", "社区智柜", "邻里宝", "生活立方", "家居宝", "社区匣", "邻里智柜", "生活宝", "家居仓", "社区立方", "邻里匣", "生活捷柜", "家居速柜", "社区安柜", "邻里稳柜", "生活信柜", "家居固柜", "社区密柜", "邻里保柜", "生活易柜", "家居捷柜", "智管柜", "柜助手", "小智匣", "慧管家", "智助柜", "柜小宝", "小慧仓", "智服柜", "柜小秘", "小智仓", "慧助柜", "柜智侠", "小秘柜", "智侠柜", "柜慧宝", "小服柜", "智宝柜", "柜小智", "慧侠柜", "智秘柜", "云储柜", "智能仓", "云端匣", "数存柜", "云枢仓", "智数匣", "云端柜", "数据仓", "云智匣", "数智柜", "云仓柜", "智枢匣", "云端仓", "数据柜", "云匣柜", "数枢仓", "云智柜", "智数据", "云数仓", "易拿柜", "快取柜", "畅存柜", "顺取柜", "易畅柜", "畅取柜", "顺存柜", "易顺柜", "快畅柜", "畅存仓", "顺取仓", "易取仓", "快顺柜", "畅顺柜", "顺存仓", "易存仓", "快取仓", "畅取仓", "顺易柜", "智享柜", "乐享存", "智悦柜", "悦存仓", "智得柜", "乐得柜", "智欢柜", "欢存柜", "智活柜", "活存仓", "智乐柜", "乐取柜", "智享仓", "悦取柜", "智活仓", "欢取柜", "智得仓", "乐存柜", "智悦仓", "活得柜", "柜便利", "智匣子", "存易得", "速柜通", "易柜达", "智存客", "柜速达", "存易通", "智柜侠"];

View File

@ -2,7 +2,7 @@ export const paymentMethodOptions = [
{ label: '微信支付', value: 0, type: 'primary' },
{ label: '借呗支付', value: 1, type: 'success' },
{ label: '要呗支付', value: 2, type: 'info' },
{ label: '余额支付', value: 3, type: 'warning' },
{ label: '借呗支付', value: 3, type: 'warning' },
];
export const modeToPaymentMethodMap = {

View File

@ -16,6 +16,7 @@ export interface FormDTO {
availableStatus: number;
usageStatus: number;
stock: number;
cellPrice?: number;
}
const props = defineProps({
@ -26,6 +27,10 @@ const props = defineProps({
row: {
type: Object,
default: null
},
mode: {
type: Number,
default: null
}
});
@ -40,7 +45,8 @@ const formData = reactive<FormDTO>({
cellType: 1,
availableStatus: 1,
usageStatus: 1,
stock: 0
stock: 0,
cellPrice: 0
});
const rules = reactive<FormRules>({
@ -129,6 +135,10 @@ watch(() => props.row, (val) => {
<el-option label="超大格" :value="4" />
</el-select>
</el-form-item>
<el-form-item v-if="props.mode == 3" label="格口价格" class="price-input-item">
<el-input v-model="formData.cellPrice" placeholder="请输入格口价格" style="width: 120px; margin-right: 10px;" />
</el-form-item>
<el-form-item v-if="props.row.goodsId" label="商品ID">
<el-input :model-value="props.row.goodsId" disabled />
@ -161,4 +171,14 @@ watch(() => props.row, (val) => {
.save-btn, .clear-btn {
margin-right: 10px;
}
.price-input-item .el-input__wrapper {
border-radius: 6px;
border-color: #dcdfe6;
box-shadow: 0 0 0 0 rgba(144, 147, 153, 0);
transition: all 0.3s;
}
.price-input-item .el-input__wrapper:focus-within {
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
</style>

View File

@ -310,7 +310,8 @@ onMounted(() => {
<div class="info-details" v-if="activeTab === 'basic'">
<div style="display: flex; justify-content: flex-end; margin-bottom: 16px;">
<el-button v-if="hasPermission('shop:cabinet:write')" type="primary" link :icon="useRenderIcon(EditPen)" @click="editCabinetDrawerVisible = true">
<el-button v-if="hasPermission('shop:cabinet:write')" type="primary" link :icon="useRenderIcon(EditPen)"
@click="editCabinetDrawerVisible = true">
编辑柜体
</el-button>
</div>
@ -320,11 +321,13 @@ onMounted(() => {
<el-descriptions-item label="柜体格式">{{ CabinetImgMap[cabinetInfo.templateNo]?.name || '-'
}}</el-descriptions-item>
<el-descriptions-item label="柜体地址">{{ cabinetInfo.shopName || '-' }}
<el-button v-if="hasPermission('shop:cabinet:write')" type="success" link @click="shopConfigVisible = true">
<el-button v-if="hasPermission('shop:cabinet:write')" type="success" link
@click="shopConfigVisible = true">
配置
</el-button></el-descriptions-item>
<el-descriptions-item label="柜体网关">{{ cabinetInfo.mqttServerId || '-' }}
<el-button v-if="hasPermission('shop:cabinet:write')" type="warning" link @click="gatewayConfigVisible = true">
<el-button v-if="hasPermission('shop:cabinet:write')" type="warning" link
@click="gatewayConfigVisible = true">
配置
</el-button></el-descriptions-item>
<el-descriptions-item label="借呗支付">{{ getBalanceEnableText(shopInfo.balanceEnable)
@ -369,7 +372,7 @@ onMounted(() => {
</svg>
<div class="cell-info">
<!-- <div class="cell-no">格口号: {{ item.cellNo }}</div> -->
<div class="price">价格: {{ item.price }}</div>
<div class="price">价格: {{ shopInfo?.mode == 3 ? item.cellPrice : item.price }}</div>
<div class="stock">库存: {{ item.stock }}</div>
<!-- <div class="cell-type">类型: {{ switchCellType(item.cellType) }}</div> -->
</div>
@ -380,16 +383,19 @@ onMounted(() => {
<span class="line-number">{{ item.cellNo }}</span>
</div>
<div class="action-buttons">
<el-button v-if="!item.goodsId" :disabled="!hasPermission('shop:cabinet:write')"
link type="success"
@click="handleConfigure(item)" class="cell-btn">
<el-button v-if="!item.goodsId && (!shopInfo || shopInfo.mode !== 3)"
:disabled="!hasPermission('shop:cabinet:write')" link type="success" @click="handleConfigure(item)"
class="cell-btn">
商品配置
</el-button>
<el-button v-if="item.goodsId" :disabled="!hasPermission('shop:cabinet:write')"
link type="primary"
<el-button v-if="item.goodsId" :disabled="!hasPermission('shop:cabinet:write')" link type="primary"
@click="handleEditCell(item)" class="cell-btn">
{{ item.goodsName }}
</el-button>
<el-button v-if="!item.goodsId && shopInfo && shopInfo.mode == 3" :disabled="!hasPermission('shop:cabinet:write')" link type="primary"
@click="handleEditCell(item)" class="cell-btn">
格口配置
</el-button>
<!-- <el-button v-if="item.goodsId" type="warning" link :icon="useRenderIcon(EditPen)"
@click="handleStockConfig(item)">
库存
@ -414,10 +420,12 @@ onMounted(() => {
<el-table-column label="锁控板序号" prop="lockControlNo" width="120" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="{ row }">
<el-button v-if="hasPermission('shop:cabinet:write')" type="primary" link :icon="useRenderIcon(EditPen)" @click="handleEditMainboard(row)">
<el-button v-if="hasPermission('shop:cabinet:write')" type="primary" link :icon="useRenderIcon(EditPen)"
@click="handleEditMainboard(row)">
编辑
</el-button>
<el-button v-if="hasPermission('shop:cabinet:write')" type="danger" link :icon="useRenderIcon(Delete)" @click="handleDeleteMainboard(row)">
<el-button v-if="hasPermission('shop:cabinet:write')" type="danger" link :icon="useRenderIcon(Delete)"
@click="handleDeleteMainboard(row)">
删除
</el-button>
</template>
@ -450,7 +458,7 @@ onMounted(() => {
<CellFormModal v-model="cellFormVisible" :initial-cabinet-id="cabinetId" @refresh="fetchCellList" />
</el-drawer>
<el-drawer v-model="cellEditVisible" title="编辑格口" size="30%" direction="rtl">
<CellEditModal v-model="cellEditVisible" :row="currentCell" @refresh="fetchCellList" />
<CellEditModal v-model="cellEditVisible" :row="currentCell" :mode="shopInfo?.mode" @refresh="fetchCellList" />
</el-drawer>
</div>
</div>

View File

@ -6,6 +6,7 @@ import { updateSmartCabinet } from "@/api/cabinet/smart-cabinet";
import Confirm from "@iconify-icons/ep/check";
import type { FormRules } from 'element-plus';
import { CabinetImgMap } from "@/utils/cabinetImgMap";
import { cabinetNames } from "@/utils/constant/cabinet";
const props = defineProps({
visible: {
@ -75,6 +76,11 @@ const closeDialog = () => {
emit("update:modelValue", false);
};
const handleRandomName = () => {
const randomIndex = Math.floor(Math.random() * cabinetNames.length);
formData.cabinetName = cabinetNames[randomIndex];
};
const templateOptions = Object.entries(CabinetImgMap).map(([value, item]) => ({
label: item.name,
value
@ -88,7 +94,10 @@ watch(() => props.cabinetInfo, (newVal) => {
<template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
<el-form-item label="柜体名称" prop="cabinetName">
<el-input v-model="formData.cabinetName" placeholder="请输入柜体名称" />
<div class="flex items-center">
<el-input v-model="formData.cabinetName" placeholder="请输入柜体名称" style="margin-right: 8px;" />
<el-button type="default" @click="handleRandomName">随机</el-button>
</div>
</el-form-item>
<el-form-item label="柜体类型" prop="cabinetType">

View File

@ -6,6 +6,7 @@ import { type PaginationProps } from "@pureadmin/table";
import { CommonUtils } from "@/utils/common";
import { useRouter } from "vue-router";
import { CabinetImgMap } from "@/utils/cabinetImgMap";
import { getShopListApi, type ShopDTO } from "@/api/shop/shop";
import Search from "@iconify-icons/ep/search";
import Refresh from "@iconify-icons/ep/refresh";
@ -27,11 +28,13 @@ const formRef = ref();
const modalVisible = ref(false);
const searchFormParams = ref({
cabinetName: "",
cabinetType: null
cabinetType: null,
shopId: null
});
const pageLoading = ref(false);
const dataList = ref<SmartCabinetDTO[]>([]);
const shopList = ref<ShopDTO[]>([]);
const pagination = ref<PaginationProps>({
total: 0,
pageSize: 12,
@ -59,6 +62,15 @@ async function getList() {
}
}
async function getShopList() {
try {
const { data } = await getShopListApi();
shopList.value = data;
} catch (error) {
console.error("获取店铺列表失败", error);
}
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
@ -86,6 +98,7 @@ const handleViewDetail = (row: SmartCabinetDTO) => {
onMounted(() => {
getList();
getShopList();
});
</script>
@ -98,10 +111,9 @@ onMounted(() => {
<el-input @keydown.enter.prevent="onSearch" v-model="searchFormParams.cabinetName" placeholder="请输入柜体名称"
clearable class="!w-[200px]" />
</el-form-item>
<el-form-item label="" prop="cabinetType">
<el-select v-model="searchFormParams.cabinetType" placeholder="请选择柜体类型" clearable class="!w-[180px]">
<el-option label="主柜" :value="0" />
<el-option label="副柜" :value="1" />
<el-form-item label="" prop="shopId">
<el-select v-model="searchFormParams.shopId" placeholder="请选择机柜地址" clearable class="!w-[180px]">
<el-option v-for="shop in shopList" :key="shop.shopId" :label="shop.shopName" :value="shop.shopId" />
</el-select>
</el-form-item>
<el-form-item>

View File

@ -6,6 +6,7 @@ import { addSmartCabinet } from "@/api/cabinet/smart-cabinet";
import Confirm from "@iconify-icons/ep/check";
import type { FormRules } from 'element-plus';
import { CabinetImgMap } from "@/utils/cabinetImgMap";
import { cabinetNames } from "@/utils/constant/cabinet";
export interface FormDTO {
cabinetName: string;
@ -78,6 +79,11 @@ const closeDialog = () => {
emit("update:modelValue", false);
};
const handleRandomName = () => {
const randomIndex = Math.floor(Math.random() * cabinetNames.length);
formData.cabinetName = cabinetNames[randomIndex];
};
const templateOptions = Object.entries(CabinetImgMap).map(([value, item]) => ({
label: item.name,
value
@ -87,7 +93,10 @@ const templateOptions = Object.entries(CabinetImgMap).map(([value, item]) => ({
<template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
<el-form-item label="柜体名称" prop="cabinetName">
<el-input v-model="formData.cabinetName" placeholder="请输入柜体名称" />
<div class="flex items-center">
<el-input v-model="formData.cabinetName" placeholder="请输入柜体名称" style="margin-right: 8px;" />
<el-button type="default" @click="handleRandomName">随机</el-button>
</div>
</el-form-item>
<!-- <el-form-item label="柜体类型" prop="cabinetType">

View File

@ -161,16 +161,13 @@ getList();
<el-form-item prop="paymentMethod">
<el-select v-model="searchFormParams.paymentMethod" placeholder="请选择支付方式" clearable class="!w-[180px]">
<el-option label="微信支付" value="wechat" />
<el-option label="余额支付" value="balance" />
<el-option label="借呗支付" value="balance" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="useRenderIcon(Search)" @click="onSearch" class="mr-2">
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm" class="mr-2">
重置
</el-button>
<el-button type="success" :loading="exportLoading" :icon="useRenderIcon('vscode-icons:file-type-excel2')"
@click="handleExport">
导出Excel
@ -202,7 +199,7 @@ getList();
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="100">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
{{ { wechat: '微信支付', balance: '借呗支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="退货数量" prop="returnQuantity" width="90" />
@ -287,6 +284,7 @@ getList();
margin-right: 12px;
}
}
:deep(.el-image-viewer__wrapper) {
z-index: 9999 !important;
}

View File

@ -0,0 +1,480 @@
<script setup lang="ts">
import { ref, computed, markRaw, watch, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import {
Calendar,
Briefcase,
Clock,
User,
Box,
Download,
Key,
UserFilled,
Delete,
RefreshLeft,
Check,
House,
Medal,
Document,
Money,
ArrowRight,
RefreshRight,
Wallet,
CreditCard,
Search,
Refresh
} from '@element-plus/icons-vue';
import { getReturnApprovalListApi } from '@/api/shop/approval';
import { debounce } from "@pureadmin/utils";
defineOptions({
name: "approvalCenter"
});
//
const activeMenu = ref('apply');
//
const activeTab = ref('all');
//
const searchFormParams = ref({
status: null,
searchStr: null
});
//
const pagination = ref({
pageSize: 5,
currentPage: 1,
total: 0
});
//
const pendingList = ref([]);
const processedList = ref([]);
const ccList = ref([]);
const submittedList = ref([]);
const loading = ref(false);
const multipleSelection = ref([]);
//
const applicationData = ref({
//
all: [],
//
shop: [
{ icon: markRaw(Calendar), name: '借用', color: '#f9a825' },
{ icon: markRaw(Box), name: '耗材领用', color: '#ff9800' },
{ icon: markRaw(Download), name: '商品归还', color: '#00bcd4' },
],
//
other: [
{ icon: markRaw(CreditCard), name: '借呗', color: '#00bcd4' },
{ icon: markRaw(Wallet), name: '退款', color: '#795548' }
],
});
applicationData.value.all = [...applicationData.value.shop, ...applicationData.value.other];
//
const filteredApplications = computed(() => {
const data = applicationData.value[activeTab.value] || [];
return data;
});
//
const handleMenuSelect = (index: string) => {
activeMenu.value = index;
};
//
const handleTabChange = (tab: any) => {
activeTab.value = tab.name;
};
//
const onSearch = () => {
pagination.value.currentPage = 1;
loadData();
};
//
const debouncedSearch = debounce(onSearch, 500);
//
watch(
() => searchFormParams.value.searchStr,
(newVal) => {
debouncedSearch();
}
);
//
const resetForm = () => {
Object.assign(searchFormParams.value, {
approvalId: null,
orderId: null,
goodsId: null,
status: null,
approvalTime: null,
paymentMethod: null
});
onSearch();
};
//
const handlePaginationChange = () => loadData();
//
const loadData = async () => {
if (activeMenu.value !== 'received-pending' && activeMenu.value !== 'received-processed') {
return;
}
loading.value = true;
try {
const params = {
...searchFormParams.value,
approvalType: 0,
pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage,
handleStatus: activeMenu.value === 'received-pending' ? 0 : activeMenu.value === 'received-processed' ? 1 : undefined
};
const { data } = await getReturnApprovalListApi(params);
const formattedData = data.rows.map(item => ({
...item,
statusStr: { 1: '待审核', 2: '已通过', 3: '已驳回' }[item.status],
paymentMethodStr: { wechat: '微信支付', balance: '借呗支付' }[item.paymentMethod] || item.paymentMethod
}));
switch (activeMenu.value) {
case 'received-pending': pendingList.value = formattedData; break;
case 'received-processed': processedList.value = formattedData; break;
}
pagination.value.total = data.total;
} catch (error) {
console.error('加载数据失败', error);
ElMessage.error('加载数据失败');
} finally {
loading.value = false;
}
};
//
watch(activeMenu, () => {
if (['received-pending', 'received-processed', 'cc', 'submitted-sent'].includes(activeMenu.value)) {
loadData();
}
});
//
const currentList = computed(() => {
switch (activeMenu.value) {
case 'received-pending': return pendingList.value;
case 'received-processed': return processedList.value;
case 'cc': return ccList.value;
case 'submitted-sent': return submittedList.value;
default: return [];
}
});
//
const handleCardClick = (item: any) => {
console.log('点击申请类型:', item.name);
};
//
const handleSelectionChange = (val) => {
multipleSelection.value = val;
};
onMounted(() => {
if (['received-pending', 'received-processed', 'cc', 'submitted-sent'].includes(activeMenu.value)) {
loadData();
}
});
</script>
<template>
<div class="approval-container">
<!-- 左侧导航栏 -->
<div class="sidebar">
<div class="custom-menu">
<div class="menu-item" :class="{ 'active': activeMenu === 'apply' }" @click="handleMenuSelect('apply')">
发起申请
</div>
<div class="sub-menu">
<div class="sub-menu-title"><span>我收到的</span></div>
<div class="sub-menu-items">
<div class="menu-item child" :class="{ 'active': activeMenu === 'received-pending' }"
@click="handleMenuSelect('received-pending')">待处理</div>
<div class="menu-item child" :class="{ 'active': activeMenu === 'received-processed' }"
@click="handleMenuSelect('received-processed')">已处理</div>
<div class="menu-item child" :class="{ 'active': activeMenu === 'cc' }" @click="handleMenuSelect('cc')">抄送我的
</div>
</div>
</div>
<div class="sub-menu">
<div class="sub-menu-title"><span>我提交的</span></div>
<div class="sub-menu-items">
<div class="menu-item child" :class="{ 'active': activeMenu === 'submitted-sent' }"
@click="handleMenuSelect('submitted-sent')">已提交</div>
</div>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="content">
<!-- 顶部导航标签栏+搜索 -->
<div class="content-header" v-if="activeMenu === 'apply'">
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabChange">
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="借还审批" name="shop"></el-tab-pane>
<el-tab-pane label="其他" name="other"></el-tab-pane>
</el-tabs>
</div>
<!-- 搜索表单 -->
<el-form v-if="activeMenu !== 'apply'" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color flex w-[99/100]">
<el-form-item prop="approvalId">
<el-input @keydown.enter.prevent="onSearch" v-model.number="searchFormParams.searchStr"
placeholder="请输入申请人/商品" clearable class="!w-[250px]" />
</el-form-item>
</el-form>
<!-- 列表视图 -->
<div v-if="activeMenu !== 'apply'" class="approval-list">
<el-table :data="currentList" v-loading="loading" border style="width: 100%"
@selection-change="handleSelectionChange" row-key="approvalId">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="approvalId" label="审批ID" width="100"></el-table-column>
<el-table-column prop="name" label="用户姓名" width="100"></el-table-column>
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="goodsName" label="商品名称"></el-table-column>
<el-table-column label="商品封面" width="120">
<template #default="{ row }">
<div v-if="row.coverImg" class="flex gap-2">
<el-image v-for="(img, index) in row.coverImg.split(',')" :key="index" :src="img"
:preview-src-list="row.coverImg.split(',')" :z-index="9999" :preview-teleported="true"
:hide-on-click-modal="true" fit="cover" class="rounded" width="40" height="40" />
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="goodsPrice" label="商品价格" width="100">
<template #default="{ row }">{{ row.goodsPrice }}</template>
</el-table-column>
<el-table-column prop="paymentMethodStr" label="支付方式" width="100"></el-table-column>
<el-table-column prop="returnQuantity" label="归还数量" width="100"></el-table-column>
<el-table-column prop="returnAmount" label="退款金额" width="100">
<template #default="{ row }">{{ row.returnAmount }}</template>
</el-table-column>
<el-table-column prop="createTime" label="提交时间" width="180">
<template #default="{ row }">{{ row.createTime ? new Date(row.createTime).toLocaleString() : '-'
}}</template>
</el-table-column>
<el-table-column prop="statusStr" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="{ 1: 'warning', 2: 'success', 3: 'danger' }[row.status]">{{ row.statusStr }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="approvalTime" label="审批时间" width="180">
<template #default="{ row }">{{ row.approvalTime ? new Date(row.approvalTime).toLocaleString() : '-'
}}</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button size="small" type="text">查看</el-button>
<el-button size="small" type="text" v-if="activeMenu === 'received-pending'">处理</el-button>
</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="handlePaginationChange" @current-change="handlePaginationChange" class="pagination mt-4" />
</div>
<!-- 申请类型列表 -->
<div class="application-list" v-if="activeMenu === 'apply'">
<el-row :gutter="16">
<el-col v-for="(item, index) in filteredApplications" :key="index" :xs="24" :sm="12" :md="8" :lg="6" :xl="4">
<div class="application-card" @click="handleCardClick(item)">
<el-icon class="card-icon" :style="{ color: item.color }">
<component :is="item.icon" />
</el-icon>
<div class="card-name">{{ item.name }}</div>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.approval-container {
display: flex;
height: 100vh;
overflow: hidden;
}
/* 左侧导航栏 */
.sidebar {
width: 200px;
background-color: #f8f8f8;
border-right: 1px solid #eee;
padding-top: 20px;
.custom-menu {
border-right: none;
//
.menu-item {
height: 50px;
line-height: 50px;
padding-left: 20px;
margin-bottom: 10px;
cursor: pointer;
&.active {
background-color: #f0f0f0;
color: #333333;
}
&:hover {
background-color: #f0f0f0;
color: #333333;
}
&.child {
padding-left: 40px;
margin-bottom: 5px;
}
}
//
.sub-menu {
margin-bottom: 10px;
.sub-menu-title {
height: 50px;
line-height: 50px;
padding-left: 20px;
transition: background-color 0.3s;
cursor: default;
}
.sub-menu-items {
margin-left: 10px;
}
}
}
}
/* 右侧内容区域 */
.content {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: #FFFFFF;
// +
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.el-tabs {
flex: 1;
.el-tabs__nav {
border-bottom: none;
.el-tabs__item {
padding: 0 20px;
height: 40px;
line-height: 40px;
border-radius: 8px 8px 0 0;
margin-right: 10px;
transition: background-color 0.3s;
&.is-active {
background-color: #fff;
border: 1px solid #eee;
border-bottom: none;
font-weight: bold;
}
&:hover {
background-color: #f8f8f8;
}
}
}
}
.search-input {
width: 200px;
}
}
//
.application-list {
margin-top: 20px;
}
//
.application-card {
width: 100%;
height: 120px;
margin-bottom: 12px;
border: 1px solid #eee;
border-radius: 8px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
}
.card-icon {
font-size: 40px;
margin-bottom: 10px;
}
.card-name {
font-size: 14px;
color: #333;
}
}
/* 审批列表样式 */
.approval-list {
.el-table {
overflow: hidden;
}
.el-table__header th {
background-color: #f8f9fa;
font-weight: 500;
}
.el-button--text {
color: #409eff;
&:hover {
color: #66b1ff;
}
}
}
}
</style>

View File

@ -121,8 +121,8 @@ watch(goodsId, () => {
<el-tab-pane label="基本信息" name="basic"></el-tab-pane>
<el-tab-pane label="购买记录" name="order"></el-tab-pane>
</el-tabs>
<el-button v-if="goodsInfo.belongType == 0 && hasPermission('shop:goods:write')" type="primary" @click="handleEdit(goodsInfo)"
style="margin-bottom: 12px" :size="'default'">
<el-button v-if="goodsInfo.belongType == 0 && hasPermission('shop:goods:write')" type="primary"
@click="handleEdit(goodsInfo)" style="margin-bottom: 12px" :size="'default'">
编辑商品
</el-button>
</div>
@ -179,7 +179,7 @@ watch(goodsId, () => {
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="120">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
{{ { wechat: '微信支付', balance: '借呗支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="支付时间" prop="payTime" width="180">

View File

@ -28,6 +28,7 @@ const searchFormParams = ref<OrderQuery>({
startTime: "",
endTime: "",
payTime: "",
returnStatus: null,
});
const pagination = ref({
@ -166,10 +167,16 @@ getList();
<el-option label="已退款" :value="4" />
</el-select>
</el-form-item>
<el-form-item prop="returnStatus">
<el-select v-model="searchFormParams.returnStatus" placeholder="请选择退还状态" clearable class="!w-[180px]">
<el-option label="未退还" :value="0" />
<el-option label="已退还" :value="1" />
</el-select>
</el-form-item>
<el-form-item prop="paymentMethod">
<el-select v-model="searchFormParams.paymentMethod" placeholder="请选择支付方式" clearable class="!w-[180px]">
<el-option label="微信支付" value="wechat" />
<el-option label="余额支付" value="balance" />
<el-option label="借呗支付" value="balance" />
</el-select>
</el-form-item>
</el-form>
@ -178,9 +185,6 @@ getList();
<el-button type="primary" :icon="useRenderIcon(Search)" @click="onSearch" style="margin-right: 10px;">
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm" style="margin-right: 10px;">
重置
</el-button>
<el-button type="success" :loading="exportLoading" :icon="useRenderIcon('vscode-icons:file-type-excel2')"
@click="handleExport">
导出Excel
@ -230,7 +234,7 @@ getList();
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="120">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
{{ { wechat: '微信支付', balance: '借呗支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="支付时间" prop="payTime" width="180">

View File

@ -224,7 +224,7 @@ onMounted(() => {
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="120">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
{{ { wechat: '微信支付', balance: '借呗支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="支付时间" prop="payTime" width="180">