272 lines
9.0 KiB
Vue
272 lines
9.0 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted, watch } from "vue";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
import { getGoodsInfo, GoodsDTO } from "@/api/shop/goods";
|
|
import { getOrderListApi, type OrderDTO, OrderQuery } from "@/api/shop/order";
|
|
import { ElMessage } from "element-plus";
|
|
import { useRenderIcon } from '@/components/ReIcon/src/hooks';
|
|
import EditPen from '@iconify-icons/ep/edit-pen';
|
|
import GoodsEditModal from "./goods-edit-modal.vue";
|
|
import { useBtnPermissionStore } from "@/store/modules/btnPermission";
|
|
|
|
const handleEdit = (row: GoodsDTO) => {
|
|
goodsInfo.value = row;
|
|
editModalVisible.value = true;
|
|
};
|
|
|
|
const { VITE_PUBLIC_IMG_PATH: IMG_PATH } = import.meta.env;
|
|
|
|
defineOptions({
|
|
name: "GoodsDetail"
|
|
});
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
|
|
const { hasPermission } = useBtnPermissionStore();
|
|
const goodsInfo = ref<GoodsDTO>({
|
|
goodsId: 0,
|
|
goodsName: "",
|
|
categoryId: 0,
|
|
price: 0,
|
|
stock: 0,
|
|
status: 0,
|
|
autoApproval: 0,
|
|
coverImg: "",
|
|
goodsDetail: "",
|
|
belongType: 0,
|
|
corpid: ""
|
|
});
|
|
const loading = ref(false);
|
|
const activeTab = ref('basic');
|
|
const goodsId = ref<number>(0);
|
|
const editModalVisible = ref(false);
|
|
|
|
async function fetchGoodsDetail() {
|
|
try {
|
|
loading.value = true;
|
|
const { data } = await getGoodsInfo(goodsId.value);
|
|
goodsInfo.value = data;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
goodsId.value = Number(route.query.id);
|
|
fetchGoodsDetail();
|
|
});
|
|
|
|
const orderList = ref<OrderDTO[]>([]);
|
|
const orderLoading = ref(false);
|
|
const orderPagination = ref({
|
|
pageSize: 8,
|
|
currentPage: 1,
|
|
total: 0
|
|
});
|
|
|
|
const fetchOrderList = async () => {
|
|
try {
|
|
orderLoading.value = true;
|
|
const { data } = await getOrderListApi({
|
|
goodsId: goodsId.value,
|
|
pageSize: orderPagination.value.pageSize,
|
|
pageNum: orderPagination.value.currentPage
|
|
});
|
|
orderList.value = data.rows;
|
|
orderPagination.value.total = data.total;
|
|
} finally {
|
|
orderLoading.value = false;
|
|
}
|
|
};
|
|
|
|
const onOrderSizeChange = (val: number) => {
|
|
orderPagination.value.pageSize = val;
|
|
fetchOrderList();
|
|
};
|
|
|
|
const onOrderCurrentChange = (val: number) => {
|
|
orderPagination.value.currentPage = val;
|
|
fetchOrderList();
|
|
};
|
|
|
|
watch(goodsId, () => {
|
|
fetchOrderList();
|
|
}, { immediate: true });
|
|
</script>
|
|
|
|
<template>
|
|
<div class="detail-container">
|
|
<goods-edit-modal v-model:visible="editModalVisible" :row="goodsInfo" @refresh="fetchGoodsDetail" />
|
|
<div class="flex-container">
|
|
<el-card class="goods-info-card">
|
|
<div class="goods-header">
|
|
<img :src="goodsInfo.coverImg" class="goods-image" />
|
|
<div class="goods-name">{{ goodsInfo.goodsName }}</div>
|
|
</div>
|
|
|
|
<el-divider />
|
|
|
|
<el-descriptions class="goods-details" :column="1" border>
|
|
<el-descriptions-item label="名称">{{ goodsInfo.goodsName }}</el-descriptions-item>
|
|
<el-descriptions-item label="价格">{{ goodsInfo.price }}</el-descriptions-item>
|
|
<el-descriptions-item label="库存">{{ goodsInfo.stock }}</el-descriptions-item>
|
|
<el-descriptions-item label="状态">{{ goodsInfo.status === 1 ? '已上架' : '已下架' }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-card>
|
|
|
|
<el-card class="info-card">
|
|
<div class="tab-header">
|
|
<el-tabs type="card" v-model="activeTab" class="tab-header-card">
|
|
<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>
|
|
</div>
|
|
|
|
<div class="info-details" v-if="activeTab === 'basic'">
|
|
<el-descriptions :column="2" border>
|
|
<el-descriptions-item label="名称">{{ goodsInfo.goodsName }}</el-descriptions-item>
|
|
<el-descriptions-item label="价格">{{ goodsInfo.price }}</el-descriptions-item>
|
|
<el-descriptions-item label="库存">{{ goodsInfo.stock }}</el-descriptions-item>
|
|
<el-descriptions-item label="已分配库存">{{ goodsInfo.totalStock }}</el-descriptions-item>
|
|
<el-descriptions-item label="状态">{{ goodsInfo.status === 1 ? '已上架' : '已下架' }}</el-descriptions-item>
|
|
<el-descriptions-item label="自动审批">{{ goodsInfo.autoApproval === 1 ? '开启' : '关闭' }}</el-descriptions-item>
|
|
<el-descriptions-item label="商品描述" :span="2">
|
|
<div v-html="goodsInfo.goodsDetail"></div>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="关联状态" :span="2">
|
|
{{ goodsInfo.cellNoStr ? '已上柜' : '未上柜' }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="关联柜址">{{ goodsInfo.shopNameStr }}</el-descriptions-item>
|
|
<el-descriptions-item label="柜体名称">{{ goodsInfo.cabinetName }}</el-descriptions-item>
|
|
<el-descriptions-item label="柜体格号">{{ goodsInfo.cellNoStr }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
</div>
|
|
|
|
<div class="order-details" v-if="activeTab === 'order'">
|
|
<el-table v-loading="orderLoading" :data="orderList" row-key="orderId" border>
|
|
<el-table-column label="订单ID" prop="orderId" width="120" />
|
|
<el-table-column label="商品名称" prop="goodsNames">
|
|
<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="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="orderPagination.currentPage" v-model:page-size="orderPagination.pageSize"
|
|
:page-sizes="[8, 10, 20, 50]" layout="total, sizes, prev, pager, next, jumper"
|
|
:total="orderPagination.total" @size-change="onOrderSizeChange" @current-change="onOrderCurrentChange"
|
|
class="pagination" />
|
|
</div>
|
|
|
|
<div class="sales-details" v-if="activeTab === 'sales'">
|
|
<!-- 销售记录表格 -->
|
|
</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: 12px;
|
|
min-height: 0;
|
|
|
|
.goods-info-card {
|
|
width: 20%;
|
|
height: 88vh;
|
|
}
|
|
|
|
.info-card {
|
|
width: 80%;
|
|
height: 88vh;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
|
|
.goods-header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
|
|
.goods-image {
|
|
width: 100%;
|
|
height: 320px;
|
|
object-fit: contain;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.goods-name {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
|
|
.tab-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 0px;
|
|
|
|
.tab-header-card {
|
|
flex: 1;
|
|
margin-right: 10px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.order-details {
|
|
margin-top: 8px;
|
|
background-color: var(--el-bg-color);
|
|
border-radius: 4px;
|
|
padding: 16px;
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
|
|
.pagination {
|
|
margin-top: 10px;
|
|
}
|
|
}
|
|
</style> |