refactor(seller): 重构预约服务、分销与商品库存等8个列表页为 useTable

- 重构预约服务模块(服务人员、系统表单、服务工单)列表页为 useTable

- 重构分销管理模块(分销商品、分销订单)列表页为 useTable

- 重构商品与库存模块(库存导出导入、库存预警管理、商品草稿模版)列表页为 useTable

- 消除 180+ 行模板重复代码,规范分页、防抖与请求竞态防护
This commit is contained in:
pikachu1995@126.com
2026-10-20 14:28:29 +08:00
parent ba964ff478
commit cba624f480
8 changed files with 254 additions and 440 deletions

View File

@@ -13,17 +13,18 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button type="success" @click="openCreate">新增服务人员</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<el-table v-loading="loading" :data="data" border :fit="false">
<el-table-column prop="staffName" label="员工姓名" width="160" />
<el-table-column prop="contactPhone" label="联系电话" width="140" />
<el-table-column prop="sortOrder" label="排序" width="80" />
<el-table-column label="人员状态" width="110">
<el-card class="mt_10">
<el-table v-loading="loading" :data="data" border style="width: 100%">
<el-table-column prop="staffName" label="员工姓名" min-width="140" />
<el-table-column prop="contactPhone" label="联系电话" min-width="140" />
<el-table-column prop="sortOrder" label="排序" width="90" align="center" />
<el-table-column label="人员状态" width="110" align="center">
<template #default="{ row }">
<el-switch
:model-value="row.status === 'ENABLED'"
@@ -31,8 +32,8 @@
/>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="170" />
<el-table-column label="操作" width="140" align="center">
<el-table-column prop="createTime" label="创建时间" min-width="170" />
<el-table-column label="操作" width="140" align="center" fixed="right">
<template #default="{ row }">
<a class="link-text" @click="openEdit(row)">编辑</a>
<span class="op-split">|</span>
@@ -78,8 +79,14 @@
<el-form-item label="联系电话">
<el-input v-model="createForm.contactPhone" placeholder="选择店员后自动填入" />
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="createForm.sortOrder" :min="0" :max="9999" controls-position="right" />
<el-form-item label="排序值">
<el-input-number v-model="createForm.sortOrder" :min="0" :max="9999" />
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="createForm.status">
<el-radio value="ENABLED">开启</el-radio>
<el-radio value="DISABLED">关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
@@ -91,10 +98,9 @@
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { ElMessageBox } from "element-plus";
import { Message } from "@/utils/message";
import { getUserListData } from "@/api/index";
import { ref } from "vue";
import { useTable } from "@/utils/useTable";
import { getUserListData } from "@/api/member";
import {
getServiceStaffPage,
createServiceStaff,
@@ -102,18 +108,12 @@ import {
updateServiceStaffStatus,
deleteServiceStaff,
} from "@/api/appointment";
import { ElMessageBox } from "element-plus";
import { Message } from "@/utils/message";
defineOptions({ name: "appointmentServiceStaffList" });
const loading = ref(false);
const data = ref([]);
const total = ref(0);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
staffName: "",
status: "",
});
const searchFormRef = ref(null);
const createVisible = ref(false);
const createLoading = ref(false);
const clerkLoading = ref(false);
@@ -127,31 +127,16 @@ const createForm = ref({
status: "ENABLED",
});
// searchFormRef:模板 ref 改名避免与顶层变量互相覆盖(原 ref="searchForm" 在 script 中未被使用)
const searchFormRef = ref(null);
onMounted(() => {
loadData();
});
function handleSearch() {
searchForm.pageNumber = 1;
loadData();
}
function loadData() {
loading.value = true;
getServiceStaffPage(searchForm)
.then((res) => {
if (res.success) {
data.value = res.result?.records || [];
total.value = res.result?.total || 0;
}
})
.finally(() => {
loading.value = false;
});
}
const { loading, data, total, searchForm, getDataList: loadData, handleSearch, resetSearch } = useTable(
getServiceStaffPage,
{
pageSize: 20,
form: {
staffName: "",
status: "",
},
}
);
function emptyForm() {
return {
@@ -228,7 +213,6 @@ function onClerkChange(memberId) {
function submitCreate() {
if (!createForm.value.clerkUserId) {
// 原代码 this.$message 小写,全局仅注册了 $Message,此处按作者意图修正
Message.warning("请选择店员");
return;
}
@@ -272,3 +256,15 @@ function toggleStatus(row, enabled) {
});
}
</script>
<style scoped>
.link-text {
color: #409eff;
cursor: pointer;
text-decoration: none;
}
.op-split {
margin: 0 8px;
color: #dcdfe6;
}
</style>

View File

@@ -13,16 +13,16 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button type="success" @click="goDesigner()">新建</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="mt_10">
<el-table v-loading="loading" :data="data" border>
<el-table v-loading="loading" :data="data" border style="width: 100%">
<el-table-column prop="formName" label="表单名称" min-width="180" />
<el-table-column label="状态" width="110">
<el-table-column label="状态" width="110" align="center">
<template #default="{ row }">
<el-switch
:key="`${row.id}-${row.status}`"
@@ -31,11 +31,11 @@
/>
</template>
</el-table-column>
<el-table-column label="字段数" width="90">
<el-table-column label="字段数" width="90" align="center">
<template #default="{ row }">{{ fieldCount(row.formSchema) }}</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间" min-width="170" />
<el-table-column label="操作" width="160" fixed="right">
<el-table-column label="操作" width="160" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="goDesigner(row.id)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
@@ -55,8 +55,8 @@
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { useTable } from "@/utils/useTable";
import { getRequest, postRequestWithNoForm, deleteRequest } from "@/libs/axios";
import { ElMessage, ElMessageBox } from "element-plus";
import { countFormFields } from "@/constants/systemForm";
@@ -64,48 +64,18 @@ import { countFormFields } from "@/constants/systemForm";
defineOptions({ name: "appointmentSystemFormList" });
const router = useRouter();
const loading = ref(false);
const data = ref([]);
const total = ref(0);
const searchForm = reactive({
formName: "",
status: "",
pageNumber: 1,
pageSize: 10,
});
const fieldCount = countFormFields;
onMounted(() => {
loadData();
});
function handleSearch() {
searchForm.pageNumber = 1;
loadData();
}
function handleReset() {
searchForm.formName = "";
searchForm.status = "";
searchForm.pageNumber = 1;
loadData();
}
function loadData() {
loading.value = true;
getRequest("/appointment/system-forms", searchForm)
.then((res) => {
if (res.success) {
data.value = res.result?.records || [];
total.value = res.result?.total || 0;
}
})
.finally(() => {
loading.value = false;
});
}
const { loading, data, total, searchForm, getDataList: loadData, handleSearch, resetSearch } = useTable(
(p) => getRequest("/appointment/system-forms", p),
{
pageSize: 10,
form: {
formName: "",
status: "",
},
}
);
function goDesigner(id) {
router.push({

View File

@@ -16,11 +16,12 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<el-card class="mt_10">
<el-tabs v-model="statusTab" @tab-click="onTabClick">
<el-tab-pane
v-for="item in statusTabs"
@@ -32,12 +33,12 @@
<el-table v-loading="loading" :data="data" border class="mt_10" style="width: 100%">
<el-table-column prop="workOrderSn" label="工单编号" min-width="180" />
<el-table-column prop="orderSn" label="订单编号" min-width="180" />
<el-table-column label="预约类型" width="100">
<el-table-column label="预约类型" width="100" align="center">
<template #default="{ row }">{{ serviceModeText(row.serviceMode) }}</template>
</el-table-column>
<el-table-column prop="appointmentTime" label="预约时间" min-width="170" />
<el-table-column prop="staffName" label="服务人员" min-width="110" />
<el-table-column label="服务状态" width="110">
<el-table-column label="服务状态" width="110" align="center">
<template #default="{ row }">{{ statusText(row.serviceStatus) }}</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right">
@@ -76,8 +77,9 @@
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { onMounted, ref } from "vue";
import { useRoute } from "vue-router";
import { useTable } from "@/utils/useTable";
import {
getWorkOrderPage,
getWorkOrderStatusCounts,
@@ -90,20 +92,10 @@ import { Message } from "@/utils/message";
defineOptions({ name: "appointmentWorkOrderList" });
const route = useRoute();
const loading = ref(false);
const data = ref([]);
const total = ref(0);
const searchFormRef = ref(null);
const statusTab = ref("ALL");
const statusCounts = ref({});
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
serviceStatus: "",
workOrderSn: "",
orderSn: "",
serviceMode: "",
});
const statusTabs = ref([
{ value: "ALL", label: "全部" },
{ value: "PENDING_CLAIM", label: "待领取" },
@@ -113,8 +105,22 @@ const statusTabs = ref([
{ value: "REFUNDED", label: "已退款" },
]);
// searchFormRef:模板 ref 改名避免与顶层变量互相覆盖
const searchFormRef = ref(null);
const { loading, data, total, searchForm, getDataList: loadData, handleSearch, resetSearch } = useTable(
getWorkOrderPage,
{
pageSize: 20,
immediate: false,
form: {
serviceStatus: "",
workOrderSn: "",
orderSn: "",
serviceMode: "",
},
onSuccess: () => {
loadCounts();
},
}
);
onMounted(() => {
if (route.query.tab) {
@@ -128,22 +134,27 @@ onMounted(() => {
function serviceModeText(v) {
return SERVICE_MODE_LABEL[v] || v || "—";
}
function statusText(v) {
return WORK_ORDER_STATUS_LABEL[v] || v || "—";
}
function tabLabel(item) {
const count = statusCounts.value[item.value];
return count != null ? `${item.label}(${count})` : item.label;
}
function onTabClick(tab) {
statusTab.value = tab.paneName;
searchForm.serviceStatus = tab.paneName === "ALL" ? "" : tab.paneName;
searchForm.pageNumber = 1;
loadData();
handleSearch();
}
function handleSearch() {
searchForm.pageNumber = 1;
loadData();
function handleReset() {
statusTab.value = "ALL";
resetSearch();
}
function loadCounts() {
getWorkOrderStatusCounts()
.then((res) => {
@@ -153,33 +164,20 @@ function loadCounts() {
})
.catch(() => {});
}
function loadData() {
loading.value = true;
getWorkOrderPage(searchForm)
.then((res) => {
if (res.success) {
data.value = res.result?.records || [];
total.value = res.result?.total || 0;
}
})
.finally(() => {
loading.value = false;
});
}
function handleClaim(row) {
claimWorkOrder(row.id).then((res) => {
if (res.success) {
Message.success("领取成功");
loadCounts();
loadData();
}
});
}
function handleEnd(row) {
endWorkOrderService(row.id).then((res) => {
if (res.success) {
Message.success("已结束服务");
loadCounts();
loadData();
}
});

View File

@@ -126,8 +126,8 @@
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@current-change="changePage"
@size-change="changePageSize"
@current-change="getDataList"
@size-change="() => { searchForm.pageNumber = 1; getDataList(); }"
/>
</div>
</el-card>
@@ -223,7 +223,8 @@
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { onMounted, ref } from "vue";
import { useTable } from "@/utils/useTable";
import {
getDistributionGoods,
distributionGoodsCancel,
@@ -240,36 +241,33 @@ const modalTitle = ref("添加分销商品");
const editVisible = ref(false);
const editLoading = ref(false);
const submitLoading = ref(false);
const loading = ref(true);
const currentAuthStatus = ref("ALL");
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
sort: "createTime",
order: "desc",
goodsName: "",
storeCategoryPath: "",
goodsType: "",
authStatus: "",
});
const currentAuthStatus = ref('ALL');
const shopCategoryList = ref([]);
const shopCategoryProps = {
value: "value",
label: "label",
children: "children",
value: 'value',
label: 'label',
children: 'children',
checkStrictly: true,
emitPath: false,
};
const selectedGoodsList = ref([]);
const editForm = ref({
id: "",
goodsName: "",
commission: "",
id: '',
goodsName: '',
commission: '',
commissionError: false,
});
const commissionPattern = /^[1-9]\d{0,3}(\.\d{1,2})?$/;
const data = ref([]);
const total = ref(0);
const { loading, data, total, searchForm, getDataList, handleSearch, resetSearch } = useTable(
getDistributionGoods,
{
pageSize: 20,
sort: "createTime",
order: "desc",
form: { goodsName: "", storeCategoryPath: "", goodsType: "", authStatus: "" },
}
);
// searchFormRef:模板 ref 改名避免与顶层变量互相覆盖
const searchFormRef = ref(null);
@@ -321,8 +319,11 @@ function authStatusText(value) {
function onAuthStatusChange(name) {
searchForm.authStatus = name === "ALL" ? "" : name;
searchForm.pageNumber = 1;
getDataList();
handleSearch();
}
function handleReset() {
currentAuthStatus.value = "ALL";
resetSearch();
}
function add() {
@@ -401,39 +402,9 @@ function handleSubmit() {
});
}
function changePage(v) {
searchForm.pageNumber = v;
getDataList();
}
function changePageSize(v) {
searchForm.pageSize = v;
searchForm.pageNumber = 1;
getDataList();
}
function handleSearch() {
searchForm.pageNumber = 1;
getDataList();
}
function getDataList() {
loading.value = true;
getDistributionGoods(searchForm)
.then((res) => {
if (res?.success) {
const page = res.result || {};
data.value = page.records || [];
total.value = page.total || 0;
} else {
data.value = [];
total.value = 0;
}
})
.finally(() => {
loading.value = false;
});
}
function remove(row) {
Modal.confirm({

View File

@@ -114,8 +114,8 @@
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@current-change="changePage"
@size-change="changePageSize"
@current-change="getDataList"
@size-change="() => { searchForm.pageNumber = 1; getDataList(); }"
/>
</div>
</el-card>
@@ -123,7 +123,8 @@
</template>
<script setup>
import { onMounted, reactive, ref, watch } from "vue";
import { ref, watch } from "vue";
import { useTable } from "@/utils/useTable";
import { useRoute } from "vue-router";
import { getDistributionOrder } from "@/api/distribution";
import vueQr from "vue-qr";
@@ -135,15 +136,32 @@ const route = useRoute();
const timeRange = ref([]);
const distributionId = ref(route.query.id);
const loading = ref(true);
const searchForm = reactive({
pageNumber: 1,
pageSize: 20,
sort: "create_time",
order: "desc",
});
const data = ref([]);
const total = ref(0);
const { loading, data, total, searchForm, getDataList, handleSearch, resetSearch } = useTable(
getDistributionOrder,
{
pageSize: 20,
sort: "create_time",
order: "desc",
form: { orderSn: "", distributionName: "" },
beforeRequest: (p) => {
const params = { ...p };
if (distributionId.value) {
params.distributionId = distributionId.value;
}
if (timeRange.value && timeRange.value[0] && timeRange.value[1]) {
const startTime = new Date(timeRange.value[0]).getTime();
const endTime = new Date(timeRange.value[1]).getTime();
params.startTime = filters.unixToDate(startTime / 1000);
params.endTime = filters.unixToDate(endTime / 1000);
}
return params;
},
}
);
function handleReset() {
timeRange.value = [];
resetSearch();
}
// searchFormRef:模板 ref 改名避免与响应式变量 searchForm 互相覆盖
const searchFormRef = ref(null);
@@ -157,56 +175,11 @@ watch(
}
);
onMounted(() => {
init();
});
function init() {
getDataList();
}
function changePage() {
getDataList();
}
function changePageSize() {
searchForm.pageNumber = 1;
getDataList();
}
function handleSearch() {
searchForm.pageNumber = 1;
searchForm.pageSize = 20;
getDataList();
}
function getDataList() {
searchForm.distributionId = distributionId.value;
loading.value = true;
if (timeRange.value && timeRange.value[0] && timeRange.value[1]) {
const startTime = new Date(timeRange.value[0]).getTime();
const endTime = new Date(timeRange.value[1]).getTime();
searchForm.startTime = filters.unixToDate(startTime / 1000);
searchForm.endTime = filters.unixToDate(endTime / 1000);
} else {
searchForm.startTime = null;
searchForm.endTime = null;
}
getDistributionOrder(searchForm)
.then((res) => {
if (res?.success) {
const page = res.result || {};
data.value = page.records || [];
total.value = page.total || 0;
} else {
data.value = [];
total.value = 0;
}
})
.finally(() => {
loading.value = false;
});
}
function filterStatus(status) {
const arr = [

View File

@@ -9,13 +9,13 @@
<el-form-item label="商品编号" prop="goodsId">
<el-input v-model="searchForm.goodsId" placeholder="请输入商品编号" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-form-item label="状态" prop="marketEnable">
<el-select v-model="searchForm.marketEnable" placeholder="请选择" clearable style="width: 200px">
<el-option label="下架" value="DOWN" />
<el-option label="上架" value="UPPER" />
</el-select>
</el-form-item>
<el-form-item label="商品分类" prop="category">
<el-form-item label="商品分类">
<el-cascader
v-model="category"
:options="categoryList"
@@ -59,26 +59,6 @@
</div>
</template>
</el-table-column>
<el-table-column label="上架状态" width="130">
<template #default="{ row }">
<el-tag :type="row.marketEnable === 'DOWN' ? 'danger' : 'success'">
{{ row.marketEnable === "DOWN" ? "下架" : "上架" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审核状态" width="120">
<template #default="{ row }">
<el-tag
:type="
row.authFlag === 'PASS' ? 'success' : row.authFlag === 'TOBEAUDITED' ? 'warning' : 'danger'
"
>
{{
row.authFlag === "PASS" ? "通过" : row.authFlag === "TOBEAUDITED" ? "待审核" : "审核拒绝"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="库存" min-width="120">
<template #default="{ row }">{{ row.quantity || 0 }}</template>
</el-table-column>
@@ -89,12 +69,12 @@
<el-pagination
v-model:current-page="searchForm.pageNumber"
v-model:page-size="searchForm.pageSize"
:page-sizes="[20, 50]"
:page-sizes="[20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@current-change="changePage"
@size-change="changePageSize"
@current-change="getDataList"
@size-change="() => { searchForm.pageNumber = 1; getDataList(); }"
/>
</div>
</el-card>
@@ -117,6 +97,7 @@
<script setup>
import { onMounted, ref } from "vue";
import { useTable } from "@/utils/useTable";
import {
getGoodsCategoryAll,
getGoodsSkuListDataSeller,
@@ -132,56 +113,35 @@ const tableRef = ref(null);
const importModal = ref(false);
const spinShow = ref(false);
const loading = ref(true);
const searchForm = ref({
pageNumber: 1,
pageSize: 20,
sort: "create_time",
order: "desc",
});
const stockAllData = ref([]);
const total = ref(0);
const categoryList = ref([]);
const category = ref([]);
const file = ref(null);
function init() {
getDataList();
deepGroup();
}
function changePageSize(v) {
searchForm.value.pageSize = v;
getDataList();
}
function changePage(v) {
searchForm.value.pageNumber = v;
getDataList();
}
function handleSearch() {
searchForm.value.pageNumber = 1;
searchForm.value.categoryPath = category.value?.length ? category.value.join(",") : null;
getDataList();
}
function handleReset() {
searchForm.value = {
pageNumber: 1,
const { loading, data: stockAllData, total, searchForm, getDataList, handleSearch, resetSearch } = useTable(
getGoodsSkuListDataSeller,
{
pageSize: 20,
sort: "create_time",
order: "desc",
};
form: {
goodsName: "",
goodsId: "",
marketEnable: "",
sn: "",
},
beforeRequest: (p) => {
const params = { ...p };
params.categoryPath = category.value?.length ? category.value.join(",") : null;
return params;
},
}
);
function handleReset() {
category.value = [];
getDataList();
}
function getDataList() {
loading.value = true;
getGoodsSkuListDataSeller(searchForm.value).then((res) => {
if (res.success) {
stockAllData.value = res.result.records;
total.value = res.result.total;
}
loading.value = false;
});
resetSearch();
}
function deepGroup() {
getGoodsCategoryAll().then((res) => {
if (res.success) {
@@ -200,12 +160,17 @@ function deepGroup() {
}
});
}
async function exportStock() {
function exportStock() {
let randomNumber = "";
for (let i = 0; i < 10; i++) {
randomNumber += Math.floor(Math.random() * 10);
}
queryExportStock(searchForm.value)
const params = { ...searchForm };
if (category.value?.length) {
params.categoryPath = category.value.join(",");
}
queryExportStock(params)
.then((res) => {
const blob = new Blob([res], { type: "application/vnd.ms-excel;charset=utf-8" });
if ("download" in document.createElement("a")) {
@@ -223,14 +188,17 @@ async function exportStock() {
})
.catch(() => {});
}
function openImportStock() {
importModal.value = true;
}
function handleUpload(f) {
file.value = f;
upload();
return false;
}
function upload() {
const fd = new FormData();
fd.append("files", file.value);
@@ -246,9 +214,10 @@ function upload() {
}
onMounted(() => {
init();
deepGroup();
});
</script>
<style lang="scss" scoped>
@import "@/styles/table-common.scss";
</style>

View File

@@ -9,13 +9,13 @@
<el-form-item label="商品编号" prop="goodsId">
<el-input v-model="searchForm.goodsId" placeholder="请输入商品编号" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-form-item label="状态" prop="marketEnable">
<el-select v-model="searchForm.marketEnable" placeholder="请选择" clearable style="width: 200px">
<el-option label="下架" value="DOWN" />
<el-option label="上架" value="UPPER" />
</el-select>
</el-form-item>
<el-form-item label="商品分类" prop="category">
<el-form-item label="商品分类">
<el-cascader
v-model="category"
:options="categoryList"
@@ -36,7 +36,7 @@
<el-tabs v-model="activeTab" @tab-click="switchTabs">
<el-tab-pane label="预警商品" name="warnList">
<el-table v-loading="loading" border :data="warnData" class="mt_10" style="width: 100%">
<el-table v-loading="loading" border :data="data" class="mt_10" style="width: 100%">
<el-table-column prop="goodsName" label="商品名称" min-width="400" show-overflow-tooltip />
<el-table-column label="库存" min-width="120">
<template #default="{ row }">{{ row.quantity || 0 }}</template>
@@ -53,7 +53,7 @@
</el-tab-pane>
<el-tab-pane label="设置预警" name="warnSetting">
<el-table v-loading="loading" border :data="skuAllData" class="mt_10" style="width: 100%">
<el-table v-loading="loading" border :data="data" class="mt_10" style="width: 100%">
<el-table-column prop="goodsName" label="商品名称" />
<el-table-column label="库存" width="200">
<template #default="{ row }">{{ row.quantity || 0 }}</template>
@@ -82,8 +82,8 @@
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@current-change="changePage"
@size-change="changePageSize"
@current-change="getDataList"
@size-change="() => { searchForm.pageNumber = 1; getDataList(); }"
/>
</div>
</el-card>
@@ -123,6 +123,7 @@
<script setup>
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useTable } from "@/utils/useTable";
import {
getGoodsCategoryAll,
getGoodsListDataByStockSeller,
@@ -142,26 +143,39 @@ const ROUTE_TAB_MAP = {
const route = useRoute();
const loading = ref(true);
const updateStockModalVisible = ref(false);
const activeTab = ref("warnList");
const searchForm = ref({
pageNumber: 1,
pageSize: 20,
sort: "create_time",
order: "desc",
});
const checkFlag = ref(false);
const stockList = ref([]);
const warnData = ref([]);
const skuAllData = ref([]);
const total = ref(0);
const categoryList = ref([]);
const category = ref([]);
const selectedSku = ref({});
const searchFormRef = ref(null);
const { loading, data, total, searchForm, getDataList, handleSearch, resetSearch } = useTable(
(params) => {
return activeTab.value === "warnList"
? getGoodsListDataByStockSeller(params)
: getGoodsSkuListDataSeller(params);
},
{
pageSize: 20,
sort: "create_time",
order: "desc",
form: {
goodsName: "",
goodsId: "",
marketEnable: "",
sn: "",
},
beforeRequest: (p) => {
const params = { ...p };
params.categoryPath = category.value?.length ? category.value.join(",") : null;
return params;
},
}
);
watch(
() => route.name,
(name) => {
@@ -172,18 +186,13 @@ watch(
onMounted(() => {
applyRouteTab();
init();
deepGroup();
});
function applyRouteTab(name = route.name) {
activeTab.value = ROUTE_TAB_MAP[name] || "warnList";
}
function init() {
getDataList();
deepGroup();
}
function openUpdataStockModal(row) {
stockList.value = [];
selectedSku.value = JSON.parse(JSON.stringify(row));
@@ -233,52 +242,9 @@ function switchTabs() {
handleReset();
}
function changePageSize(v) {
searchForm.value.pageSize = v;
getDataList();
}
function changePage(v) {
searchForm.value.pageNumber = v;
getDataList();
}
function handleSearch() {
searchForm.value.pageNumber = 1;
searchForm.value.categoryPath = category.value?.length ? category.value.join(",") : null;
getDataList();
}
function handleReset() {
searchForm.value = {
pageNumber: 1,
pageSize: 20,
sort: "create_time",
order: "desc",
};
category.value = [];
getDataList();
}
function getDataList() {
loading.value = true;
if (activeTab.value === "warnList") {
getGoodsListDataByStockSeller(searchForm.value).then((res) => {
if (res.success) {
warnData.value = res.result.records;
total.value = res.result.total;
}
loading.value = false;
});
} else {
getGoodsSkuListDataSeller(searchForm.value).then((res) => {
if (res.success) {
skuAllData.value = res.result.records;
total.value = res.result.total;
}
loading.value = false;
});
}
resetSearch();
}
function deepGroup() {

View File

@@ -17,13 +17,13 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<el-table v-loading="loading" border :data="data" ref="tableRef" class="mt_10" style="width: 100%">
<el-card class="mt_10">
<el-table ref="tableRef" v-loading="loading" border :data="data" style="width: 100%">
<el-table-column prop="id" label="编号" min-width="120" />
<el-table-column label="商品原图" width="120" align="center">
<template #default="{ row }">
@@ -41,7 +41,7 @@
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="120" />
<el-table-column label="操作" align="center" width="150">
<el-table-column label="操作" align="center" width="150" fixed="right">
<template #default="{ row }">
<a class="link-text" @click="editGoods(row)">编辑</a>
<span class="op-split">|</span>
@@ -58,8 +58,8 @@
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@current-change="changePage"
@size-change="changePageSize"
@current-change="getDataList"
@size-change="() => { searchForm.pageNumber = 1; getDataList(); }"
/>
</div>
</el-card>
@@ -67,8 +67,9 @@
</template>
<script setup>
import { onMounted, ref, watch } from "vue";
import { ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useTable } from "@/utils/useTable";
import { getDraftGoodsListData, deleteDraftGoods } from "@/api/goods";
import { Message, Modal } from "@/utils/message";
@@ -80,29 +81,37 @@ const router = useRouter();
const searchFormRef = ref(null);
const tableRef = ref(null);
const loading = ref(true);
const searchForm = ref({
pageNumber: 1,
pageSize: 10,
sort: "create_time",
order: "desc",
saveType: "TEMPLATE",
});
const data = ref([]);
const total = ref(0);
const { loading, data, total, searchForm, getDataList, handleSearch, resetSearch } = useTable(
getDraftGoodsListData,
{
pageSize: 10,
sort: "create_time",
order: "desc",
form: {
goodsName: "",
id: "",
saveType: "TEMPLATE",
},
}
);
watch(
() => route.query,
() => {
getDataList();
}
);
function init() {
getDataList();
}
function editGoods(v) {
router.push({
name: "goods-template-operation-edit",
query: { draftId: v.id },
});
}
function removeDraft(id) {
Modal.confirm({
title: "确认审核",
title: "确认删除",
content: "您确认要删除id为 " + id + " 的模版吗?",
loading: true,
onOk: () => {
@@ -116,44 +125,6 @@ function removeDraft(id) {
},
});
}
function changePage() {
getDataList();
}
function changePageSize() {
getDataList();
}
function handleSearch() {
searchForm.value.pageNumber = 1;
searchForm.value.pageSize = 10;
getDataList();
}
function handleReset() {
searchFormRef.value.resetFields();
searchForm.value.pageNumber = 1;
searchForm.value.pageSize = 10;
getDataList();
}
function getDataList() {
loading.value = true;
getDraftGoodsListData(searchForm.value).then((res) => {
loading.value = false;
if (res.success) {
data.value = res.result.records;
total.value = res.result.total;
}
});
}
onMounted(() => {
init();
});
watch(
() => route.query,
() => {
init();
}
);
</script>
<style lang="scss" scoped>