fix: 更新 API 请求参数格式及优化组件样式

- 将 addEvaluation API 的参数从 params 修改为 data,以符合标准请求格式
- 在多个组件中调整样式,提升响应式布局和用户体验
- 优化商品详情页的倒计时显示,增强视觉效果
- 更新购物车操作按钮样式,提升一致性和可用性
This commit is contained in:
田香琪
2026-06-23 14:13:25 +08:00
parent 8a60e23214
commit 1b2e980fb6
26 changed files with 481 additions and 401 deletions

View File

@@ -24,8 +24,8 @@
</el-card>
<el-card>
<div class="operation" style="margin: 10px 0">
<el-button type="primary" @click="delAll">批量下架</el-button>
<div class="operation">
<el-button type="primary" @click="add">添加</el-button>
</div>
<el-table
@@ -35,44 +35,35 @@
:data="data"
class="mt_10"
style="width: 100%"
@selection-change="changeSelect"
>
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="商品图片" width="120" align="center" fixed="left">
<el-table-column label="商品名称" min-width="250">
<template #default="{ row }">
<img
v-if="row"
:src="row.thumbnail || ''"
alt="商品图"
style="cursor: pointer; width: 80px; height: 60px; margin: 10px 0; object-fit: contain"
/>
</template>
</el-table-column>
<el-table-column label="商品名称" min-width="220" show-overflow-tooltip>
<template #default="{ row }">
<template v-if="row">
<div class="div-zoom">
<a class="link-text" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
</div>
<el-popover trigger="hover" title="扫码在手机中查看" placement="top" width="180">
<template #reference>
<img
src="../../assets/qrcode.svg"
class="hover-pointer"
width="20"
height="20"
alt="qrcode"
<div v-if="row" class="goods-msg">
<img :src="row.thumbnail" width="60" height="60" alt="" />
<div>
<div class="div-zoom">
<a class="link-text" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
</div>
<el-popover trigger="hover" title="扫码在手机中查看" placement="top" width="180">
<template #reference>
<img
src="../../assets/qrcode.svg"
class="hover-pointer"
width="20"
height="20"
alt="qrcode"
/>
</template>
<vue-qr
:text="wapLinkTo(row.goodsId, row.skuId)"
:margin="0"
color-dark="#000"
color-light="#fff"
:size="150"
/>
</template>
<vue-qr
:text="wapLinkTo(row.goodsId, row.skuId)"
:margin="0"
color-dark="#000"
color-light="#fff"
:size="150"
/>
</el-popover>
</template>
</el-popover>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="商品价格" min-width="110">
@@ -82,15 +73,16 @@
</el-table-column>
<el-table-column prop="quantity" label="库存" min-width="80" />
<el-table-column prop="createTime" label="添加时间" min-width="160" />
<el-table-column prop="storeName" label="店铺名称" min-width="120" show-overflow-tooltip />
<el-table-column label="佣金金额" min-width="110">
<template #default="{ row }">
<span v-if="row" :style="{ color: $mainColor }">{{ $filters.unitPrice(row.commission, "") }}</span>
<span v-if="row" :style="{ color: $mainColor }">
{{ $filters.unitPrice(row.commission ?? 0, "") }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="100" align="center" fixed="right">
<template #default="{ row }">
<a v-if="row" class="link-text" @click="remove(row)">下架</a>
<a v-if="row" class="link-text" @click="remove(row)">删除</a>
</template>
</el-table-column>
</el-table>
@@ -99,7 +91,7 @@
<el-pagination
v-model:current-page="searchForm.pageNumber"
v-model:page-size="searchForm.pageSize"
:page-sizes="[20, 50, 100]"
:page-sizes="[10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
size="small"
@@ -108,27 +100,67 @@
/>
</div>
</el-card>
<liliDialog ref="liliDialog" @selectedGoodsData="selectedGoodsData" />
<el-dialog
v-model="modalVisible"
:title="modalTitle"
width="500px"
:close-on-click-modal="false"
append-to-body
>
<el-form ref="form" :model="form" label-width="100px" :rules="formValidate">
<el-form-item label="分销佣金" prop="commission">
<el-input v-model="form.commission" clearable placeholder="请输入分销佣金" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="modalVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">提交</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import { delDistributionGoods, getDistributionGoods } from "@/api/distribution";
import {
getDistributionGoods,
distributionGoodsCancel,
distributionGoodsCheck,
} from "@/api/distribution";
import liliDialog from "@/views/lili-dialog";
import vueQr from "vue-qr";
export default {
name: "distributionGoods",
components: { vueQr },
components: { liliDialog, vueQr },
data() {
return {
modalVisible: false,
modalTitle: "添加分销商品",
submitLoading: false,
loading: true,
searchForm: {
pageNumber: 1,
pageSize: 20,
pageSize: 10,
sort: "createTime",
order: "desc",
},
selectList: [],
selectCount: 0,
form: {
commission: 1,
},
skuId: 0,
formValidate: {
commission: [
{ required: true, message: "请输入大于1小于9999的合法佣金金额", trigger: "blur" },
{
pattern: /^[1-9]\d{0,3}(\.\d{1,2})?$/,
message: "请输入大于1小于9999的合法佣金金额",
trigger: "blur",
},
],
},
data: [],
total: 0,
};
@@ -137,72 +169,74 @@ export default {
init() {
this.getDataList();
},
add() {
this.$refs.liliDialog.goodsData = [];
this.$refs.liliDialog.open("goods", "single");
},
selectedGoodsData(selected) {
if (!selected?.length) return;
this.modalVisible = true;
this.form.commission = 1;
this.modalTitle = "添加分销商品";
this.skuId = selected[0].id;
},
handleSubmit() {
this.$refs.form.validate((valid) => {
if (!valid) return;
this.submitLoading = true;
distributionGoodsCheck(this.skuId, this.form)
.then((res) => {
if (res?.success || res?.message === "success") {
this.$Message.success("添加成功");
}
this.modalVisible = false;
this.getDataList();
})
.finally(() => {
this.submitLoading = false;
});
});
},
changePage(v) {
this.searchForm.pageNumber = v;
this.getDataList();
this.clearSelectAll();
},
changePageSize(v) {
this.searchForm.pageSize = v;
this.searchForm.pageNumber = 1;
this.getDataList();
},
handleSearch() {
this.searchForm.pageNumber = 1;
this.searchForm.pageSize = 20;
this.getDataList();
},
clearSelectAll() {
this.$refs.table?.clearSelection();
},
changeSelect(e) {
this.selectList = e;
this.selectCount = e.length;
},
getDataList() {
this.loading = true;
getDistributionGoods(this.searchForm)
.then((res) => {
if (res.success) {
this.data = res.result.records;
this.total = res.result.total;
if (res?.success) {
const page = res.result || {};
this.data = page.records || [];
this.total = page.total || 0;
} else {
this.data = [];
this.total = 0;
}
})
.finally(() => {
this.loading = false;
});
},
remove(v) {
remove(row) {
this.$Modal.confirm({
title: "确认下架",
content: "您确认要下架么?",
title: "确认删除",
content: "您确认要删除此分销商品吗?",
loading: true,
onOk: () => {
delDistributionGoods(v.id).then((res) => {
distributionGoodsCancel(row.id).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("下架成功");
this.getDataList();
}
});
},
});
},
delAll() {
if (this.selectCount <= 0) {
this.$Message.warning("您还未选择要下架的数据");
return;
}
this.$Modal.confirm({
title: "确认下架",
content: "您确认要下架所选的 " + this.selectCount + " 条数据?",
loading: true,
onOk: () => {
const ids = this.selectList.map((item) => item.id);
delDistributionGoods(ids.toString()).then((res) => {
this.$Modal.remove();
if (res.success) {
this.$Message.success("下架成功");
this.clearSelectAll();
if (res?.success) {
this.$Message.success("删除成功");
this.getDataList();
}
});
@@ -217,21 +251,39 @@ export default {
</script>
<style lang="scss" scoped>
.operation {
margin: 10px 0;
}
.goods-msg {
display: flex;
align-items: flex-start;
gap: 13px;
padding: 5px 0;
img {
object-fit: contain;
}
}
.link-text {
color: #409eff;
cursor: pointer;
text-decoration: none;
}
.div-zoom {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 4px;
}
.hover-pointer {
cursor: pointer;
vertical-align: middle;
}
.mt_10 {
margin-top: 10px;
}

View File

@@ -24,8 +24,8 @@
style="width: 200px"
/>
</el-form-item>
<el-form-item label="货号" prop="id">
<el-input v-model="searchForm.skuSn" placeholder="请输入货号" clearable style="width: 200px" />
<el-form-item label="货号" prop="sn">
<el-input v-model="searchForm.sn" placeholder="请输入货号" clearable style="width: 200px" />
</el-form-item>
<el-form-item>
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>

View File

@@ -55,22 +55,6 @@
<el-option label="虚拟商品" value="VIRTUAL_GOODS" />
</el-select>
</el-form-item>
<el-form-item label="商品分组" prop="groupId">
<el-select
v-model="searchForm.groupId"
placeholder="请选择商品分组"
clearable
filterable
style="width: 240px"
>
<el-option
v-for="item in goodsGroupList"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
</el-form-item>
@@ -90,14 +74,6 @@
</div>
<div class="batch-operations" style="margin: 10px 0">
<el-button
type="primary"
:disabled="selectedRows.length === 0"
style="margin-right: 10px"
@click="openSetGoodsGroup"
>
批量设置分组
</el-button>
<el-button
type="success"
:disabled="selectedRows.length === 0"
@@ -209,38 +185,15 @@
<el-button type="primary" :loading="submitLoading" @click="lower">提交</el-button>
</template>
</el-dialog>
<el-dialog v-model="goodsGroupFlag" title="批量设置商品分组" width="420px">
<el-form ref="goodsGroupForm" :model="goodsGroupForm" :rules="goodsGroupRule" label-width="90px">
<el-form-item label="商品分组" prop="groupId">
<el-select v-model="goodsGroupForm.groupId" clearable filterable style="width: 240px">
<el-option
v-for="item in goodsGroupList"
:key="item.id"
:label="item.groupName"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="goodsGroupFlag = false">取消</el-button>
<el-button type="primary" :loading="goodsGroupLoading" @click="submitSetGoodsGroup">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import * as API_Shop from "@/api/shops";
import {
getGoodsListData,
getGoodsNumerData,
upGoods,
lowGoods,
getGoodsGroupByPage,
addGoodsGroupItems
} from "@/api/goods";
export default {
name: "goods",
@@ -255,7 +208,6 @@ export default {
pageSize: 20, // 页面大小
sort: "create_time", // 默认排序字段
order: "desc", // 默认排序方式
groupId: "",
},
underForm: {
// 下架原因
@@ -268,15 +220,6 @@ export default {
goodsNumerData: {},
selectedRows: [], // 选中的行数据
selectAll: false, // 全选状态
goodsGroupFlag: false,
goodsGroupLoading: false,
goodsGroupList: [],
goodsGroupForm: {
groupId: ""
},
goodsGroupRule: {
groupId: [{ required: true, message: "请选择商品分组", trigger: "change" }]
}
};
},
computed: {
@@ -322,7 +265,6 @@ export default {
init() {
this.getDataList();
this.getNumberData();
this.loadGoodsGroupList();
},
// 分页 改变页码
changePage(v) {
@@ -505,49 +447,6 @@ export default {
}
});
},
loadGoodsGroupList() {
getGoodsGroupByPage({ pageNumber: 1, pageSize: 1000 }).then((res) => {
if (res && res.success && res.result) {
this.goodsGroupList = res.result.records || [];
}
});
},
openSetGoodsGroup() {
if (this.selectedRows.length === 0) {
this.$Message.warning("请先选择商品");
return;
}
this.goodsGroupFlag = true;
this.goodsGroupLoading = false;
this.goodsGroupForm = { groupId: "" };
this.$nextTick(() => {
if (this.$refs.goodsGroupForm) this.$refs.goodsGroupForm.resetFields();
});
this.loadGoodsGroupList();
},
submitSetGoodsGroup() {
this.$refs.goodsGroupForm.validate((valid) => {
if (!valid) return;
const goodsIds = this.selectedRows.map((item) => item.id);
this.goodsGroupLoading = true;
addGoodsGroupItems(this.goodsGroupForm.groupId, goodsIds).then((res) => {
this.goodsGroupLoading = false;
if (res && res.success) {
this.$Message.success("设置成功");
this.goodsGroupFlag = false;
this.selectedRows = [];
this.selectAll = false;
this.clearTableSelection();
this.getDataList();
} else if (res && res.message) {
this.$Message.error(res.message);
}
}).catch(() => {
this.goodsGroupLoading = false;
this.$Message.error("设置失败,请检查权限或后端接口");
});
});
}
},
mounted() {
this.init();

View File

@@ -82,6 +82,7 @@ export default {
data() {
return {
type: "multiple",
selectedList: [],
skuList: [],
total: 0,
goodsParams: {
@@ -106,8 +107,8 @@ export default {
this.goodsParams.categoryPath = val && val.length ? val.join(",") : "";
},
selectedWay: {
handler() {
this.$emit("selected", this.selectedWay);
handler(val) {
this.selectedList = Array.isArray(val) ? val.slice() : [];
},
deep: true,
immediate: true,
@@ -145,24 +146,29 @@ export default {
});
},
initGoods(res) {
if (res.result.records.length != 0) {
res.result.records.forEach((item) => {
const records = res?.result?.records || [];
if (records.length) {
records.forEach((item) => {
item.selected = false;
item.___type = "goods";
this.selectedWay.forEach((e) => {
this.selectedList.forEach((e) => {
if (e.id && e.id === item.id) {
item.selected = true;
}
});
});
this.total = res.result.total;
this.goodsData = res.result.records;
this.total = res.result.total || 0;
this.goodsData = records;
this.empty = false;
} else {
this.goodsData = [];
this.empty = true;
}
},
emitSelected(list) {
this.selectedList = list;
this.$emit("selected", this.selectedList);
},
init() {
API_Goods.getGoodsSkuData(this.goodsParams).then((res) => {
this.initGoods(res);
@@ -201,26 +207,20 @@ export default {
});
},
checkedGoods(val) {
if (this.type != "multiple") {
if (this.type !== "multiple") {
this.goodsData.forEach((item) => {
item.selected = false;
});
this.selectedWay = [];
val.selected = true;
this.selectedWay.push(val);
return false;
this.emitSelected([val]);
return;
}
if (val.selected == false) {
if (!val.selected) {
val.selected = true;
this.selectedWay.push(val);
this.emitSelected([...this.selectedList, val]);
} else {
val.selected = false;
for (let i = 0; i < this.selectedWay.length; i++) {
if (this.selectedWay[i].id === val.id) {
this.selectedWay.splice(i, 1);
break;
}
}
this.emitSelected(this.selectedList.filter((item) => item.id !== val.id));
}
},
},

View File

@@ -15,7 +15,7 @@
<div
v-for="(item, index) in data[plant]"
:key="index"
:class="{ active: chiosend[plantIndex]?.id == item.id }"
:class="{ active: chiosend[plantIndex] && chiosend[plantIndex].id == item.id }"
class="map-item"
@click="
init(

View File

@@ -120,7 +120,11 @@
</el-table-column>
<el-table-column label="售后状态" width="180">
<template #default="{ row }">
<el-tag v-if="row" :type="serviceStatusTagType(row.serviceStatus)">
<el-tag
v-if="row"
:type="serviceStatusTagType(row.serviceStatus)"
effect="plain"
>
{{ serviceStatusText(row.serviceStatus) }}
</el-tag>
</template>

View File

@@ -9,7 +9,7 @@
class="search-form"
@keyup.enter="handleSearch"
>
<el-form-item label="关键字" prop="keywords" style="display: block; width: 100%">
<el-form-item label="关键字" prop="keywords">
<el-input
v-model="searchForm.keywords"
placeholder="请输入商品名称、订单编号搜索"
@@ -112,7 +112,11 @@
</el-table-column>
<el-table-column label="售后状态" width="180">
<template #default="{ row }">
<el-tag v-if="row" :type="serviceStatusTagType(row.serviceStatus)">
<el-tag
v-if="row"
:type="serviceStatusTagType(row.serviceStatus)"
effect="plain"
>
{{ serviceStatusText(row.serviceStatus) }}
</el-tag>
</template>

View File

@@ -379,7 +379,8 @@ export default {
this.getDataList();
},
getOrderNumData() {
const { orderStatus, ...searchParams } = this.searchForm;
// orderNum 接口仅查 li_order不含 order_item 关联keywords/goodsName 会引用 oi 字段导致 SQL 报错
const { orderStatus, keywords, goodsName, ...searchParams } = this.searchForm;
API_Order.getOrderNum(searchParams)
.then((res) => {
if (res.success) {